blob: 47ac4ce45cc2f81a6095e8924772f31aeb52e5a7 [file] [log] [blame]
// 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/policy/device_cloud_policy_initializer.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/sequenced_task_runner.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
#include "chrome/browser/chromeos/policy/device_status_collector.h"
#include "chrome/browser/chromeos/policy/enrollment_config.h"
#include "chrome/browser/chromeos/policy/enrollment_handler_chromeos.h"
#include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h"
#include "chrome/browser/chromeos/policy/server_backed_device_state.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/pref_names.h"
#include "chromeos/attestation/attestation_flow.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/cryptohome/async_method_caller.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/dbus/attestation/attestation.pb.h"
#include "chromeos/settings/install_attributes.h"
#include "chromeos/system/statistics_provider.h"
#include "components/policy/core/common/cloud/cloud_policy_core.h"
#include "components/policy/core/common/cloud/device_management_service.h"
#include "components/policy/core/common/cloud/dm_auth.h"
#include "components/prefs/pref_service.h"
#include "net/url_request/url_request_context_getter.h"
namespace chromeos {
class ActiveDirectoryJoinDelegate;
}
namespace policy {
DeviceCloudPolicyInitializer::DeviceCloudPolicyInitializer(
PrefService* local_state,
DeviceManagementService* enterprise_service,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
chromeos::InstallAttributes* install_attributes,
ServerBackedStateKeysBroker* state_keys_broker,
DeviceCloudPolicyStoreChromeOS* device_store,
DeviceCloudPolicyManagerChromeOS* manager,
cryptohome::AsyncMethodCaller* async_method_caller,
std::unique_ptr<chromeos::attestation::AttestationFlow> attestation_flow,
chromeos::system::StatisticsProvider* statistics_provider)
: local_state_(local_state),
enterprise_service_(enterprise_service),
background_task_runner_(background_task_runner),
install_attributes_(install_attributes),
state_keys_broker_(state_keys_broker),
device_store_(device_store),
manager_(manager),
attestation_flow_(std::move(attestation_flow)),
statistics_provider_(statistics_provider),
signing_service_(std::make_unique<TpmEnrollmentKeySigningService>(
async_method_caller)) {}
void DeviceCloudPolicyInitializer::SetSigningServiceForTesting(
std::unique_ptr<policy::SigningService> signing_service) {
signing_service_ = std::move(signing_service);
}
void DeviceCloudPolicyInitializer::SetSystemURLLoaderFactoryForTesting(
scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory) {
system_url_loader_factory_for_testing_ = system_url_loader_factory;
}
DeviceCloudPolicyInitializer::~DeviceCloudPolicyInitializer() {
DCHECK(!is_initialized_);
}
void DeviceCloudPolicyInitializer::Init() {
DCHECK(!is_initialized_);
is_initialized_ = true;
device_store_->AddObserver(this);
state_keys_update_subscription_ = state_keys_broker_->RegisterUpdateCallback(
base::Bind(&DeviceCloudPolicyInitializer::TryToCreateClient,
base::Unretained(this)));
TryToCreateClient();
}
void DeviceCloudPolicyInitializer::Shutdown() {
DCHECK(is_initialized_);
device_store_->RemoveObserver(this);
enrollment_handler_.reset();
state_keys_update_subscription_.reset();
is_initialized_ = false;
}
void DeviceCloudPolicyInitializer::PrepareEnrollment(
DeviceManagementService* device_management_service,
chromeos::ActiveDirectoryJoinDelegate* ad_join_delegate,
const EnrollmentConfig& enrollment_config,
std::unique_ptr<DMAuth> dm_auth,
const EnrollmentCallback& enrollment_callback) {
DCHECK(is_initialized_);
DCHECK(!enrollment_handler_);
manager_->core()->Disconnect();
enrollment_handler_.reset(new EnrollmentHandlerChromeOS(
device_store_, install_attributes_, state_keys_broker_,
attestation_flow_.get(), CreateClient(device_management_service),
background_task_runner_, ad_join_delegate, enrollment_config,
std::move(dm_auth), install_attributes_->GetDeviceId(),
manager_->GetDeviceRequisition(),
base::Bind(&DeviceCloudPolicyInitializer::EnrollmentCompleted,
base::Unretained(this), enrollment_callback)));
}
void DeviceCloudPolicyInitializer::StartEnrollment() {
DCHECK(is_initialized_);
DCHECK(enrollment_handler_);
enrollment_handler_->StartEnrollment();
}
void DeviceCloudPolicyInitializer::CheckAvailableLicenses(
const AvailableLicensesCallback& callback) {
DCHECK(is_initialized_);
DCHECK(enrollment_handler_);
enrollment_handler_->CheckAvailableLicenses(callback);
}
void DeviceCloudPolicyInitializer::StartEnrollmentWithLicense(
policy::LicenseType license_type) {
DCHECK(is_initialized_);
DCHECK(enrollment_handler_);
DCHECK(license_type != policy::LicenseType::UNKNOWN);
enrollment_handler_->StartEnrollmentWithLicense(license_type);
}
EnrollmentConfig DeviceCloudPolicyInitializer::GetPrescribedEnrollmentConfig()
const {
EnrollmentConfig config;
// Authentication through the attestation mechanism is controlled by a
// command line switch that either enables it or forces it (meaning that
// interactive authentication is disabled).
switch (DeviceCloudPolicyManagerChromeOS::GetZeroTouchEnrollmentMode()) {
case ZeroTouchEnrollmentMode::DISABLED:
// Only use interactive authentication.
config.auth_mechanism = EnrollmentConfig::AUTH_MECHANISM_INTERACTIVE;
break;
case ZeroTouchEnrollmentMode::ENABLED:
// Use the best mechanism, which may include attestation if available.
config.auth_mechanism = EnrollmentConfig::AUTH_MECHANISM_BEST_AVAILABLE;
break;
case ZeroTouchEnrollmentMode::FORCED:
// Only use attestation to authenticate since zero-touch is forced.
config.auth_mechanism = EnrollmentConfig::AUTH_MECHANISM_ATTESTATION;
break;
case ZeroTouchEnrollmentMode::HANDS_OFF:
// Hands-off implies the same authentication method as Forced.
config.auth_mechanism = EnrollmentConfig::AUTH_MECHANISM_ATTESTATION;
break;
}
// If OOBE is done and we are not enrolled, make sure we only try interactive
// enrollment.
const bool oobe_complete = local_state_->GetBoolean(prefs::kOobeComplete);
if (oobe_complete &&
config.auth_mechanism == EnrollmentConfig::AUTH_MECHANISM_BEST_AVAILABLE)
config.auth_mechanism = EnrollmentConfig::AUTH_MECHANISM_INTERACTIVE;
// If OOBE is done and we are enrolled, check for need to recover enrollment.
// Enrollment recovery is not implemented for Active Directory.
if (oobe_complete && install_attributes_->IsCloudManaged()) {
// Regardless what mode is applicable, the enrollment domain is fixed.
config.management_domain = install_attributes_->GetDomain();
// Enrollment has completed previously and installation-time attributes
// are in place. Enrollment recovery is required when the server
// registration gets lost.
if (local_state_->GetBoolean(prefs::kEnrollmentRecoveryRequired)) {
LOG(WARNING) << "Enrollment recovery required according to pref.";
if (statistics_provider_->GetEnterpriseMachineID().empty())
LOG(WARNING) << "Postponing recovery because machine id is missing.";
else
config.mode = EnrollmentConfig::MODE_RECOVERY;
}
return config;
}
// OOBE is still running, or it is complete but the device hasn't been
// enrolled yet. In either case, enrollment should take place if there's a
// signal present that indicates the device should enroll.
// Gather enrollment signals from various sources.
const base::DictionaryValue* device_state =
local_state_->GetDictionary(prefs::kServerBackedDeviceState);
std::string device_state_restore_mode;
std::string device_state_management_domain;
if (device_state) {
device_state->GetString(kDeviceStateRestoreMode,
&device_state_restore_mode);
device_state->GetString(kDeviceStateManagementDomain,
&device_state_management_domain);
}
const bool pref_enrollment_auto_start_present =
local_state_->HasPrefPath(prefs::kDeviceEnrollmentAutoStart);
const bool pref_enrollment_auto_start =
local_state_->GetBoolean(prefs::kDeviceEnrollmentAutoStart);
const bool pref_enrollment_can_exit_present =
local_state_->HasPrefPath(prefs::kDeviceEnrollmentCanExit);
const bool pref_enrollment_can_exit =
local_state_->GetBoolean(prefs::kDeviceEnrollmentCanExit);
const bool oem_is_managed =
GetMachineFlag(chromeos::system::kOemIsEnterpriseManagedKey, false);
const bool oem_can_exit_enrollment = GetMachineFlag(
chromeos::system::kOemCanExitEnterpriseEnrollmentKey, true);
// Decide enrollment mode. Give precedence to forced variants.
if (device_state_restore_mode ==
kDeviceStateRestoreModeReEnrollmentEnforced) {
config.mode = EnrollmentConfig::MODE_SERVER_FORCED;
config.management_domain = device_state_management_domain;
} else if (device_state_restore_mode ==
kDeviceStateRestoreModeReEnrollmentZeroTouch) {
config.mode = EnrollmentConfig::MODE_ATTESTATION_SERVER_FORCED;
config.auth_mechanism = EnrollmentConfig::AUTH_MECHANISM_BEST_AVAILABLE;
config.management_domain = device_state_management_domain;
} else if (pref_enrollment_auto_start_present &&
pref_enrollment_auto_start &&
pref_enrollment_can_exit_present &&
!pref_enrollment_can_exit) {
config.mode = EnrollmentConfig::MODE_LOCAL_FORCED;
} else if (oem_is_managed && !oem_can_exit_enrollment) {
config.mode = EnrollmentConfig::MODE_LOCAL_FORCED;
} else if (oobe_complete) {
// If OOBE is complete, don't return advertised modes as there's currently
// no way to make sure advertised enrollment only gets shown once.
config.mode = EnrollmentConfig::MODE_NONE;
} else if (device_state_restore_mode ==
kDeviceStateRestoreModeReEnrollmentRequested) {
config.mode = EnrollmentConfig::MODE_SERVER_ADVERTISED;
config.management_domain = device_state_management_domain;
} else if (pref_enrollment_auto_start_present && pref_enrollment_auto_start) {
config.mode = EnrollmentConfig::MODE_LOCAL_ADVERTISED;
} else if (oem_is_managed) {
config.mode = EnrollmentConfig::MODE_LOCAL_ADVERTISED;
}
return config;
}
void DeviceCloudPolicyInitializer::OnStoreLoaded(CloudPolicyStore* store) {
TryToCreateClient();
}
void DeviceCloudPolicyInitializer::OnStoreError(CloudPolicyStore* store) {
// Do nothing.
}
void DeviceCloudPolicyInitializer::EnrollmentCompleted(
const EnrollmentCallback& enrollment_callback,
EnrollmentStatus status) {
std::unique_ptr<CloudPolicyClient> client =
enrollment_handler_->ReleaseClient();
enrollment_handler_.reset();
if (status.status() == EnrollmentStatus::SUCCESS &&
!install_attributes_->IsActiveDirectoryManaged()) {
StartConnection(std::move(client));
} else {
// Some attempts to create a client may be blocked because the enrollment
// was in progress. We give it a try again.
TryToCreateClient();
}
if (!enrollment_callback.is_null())
enrollment_callback.Run(status);
}
std::unique_ptr<CloudPolicyClient> DeviceCloudPolicyInitializer::CreateClient(
DeviceManagementService* device_management_service) {
std::string machine_model;
statistics_provider_->GetMachineStatistic(chromeos::system::kHardwareClassKey,
&machine_model);
std::string brand_code;
statistics_provider_->GetMachineStatistic(chromeos::system::kRlzBrandCodeKey,
&brand_code);
// DeviceDMToken callback is empty here because for device policies this
// DMToken is already provided in the policy fetch requests.
return std::make_unique<CloudPolicyClient>(
statistics_provider_->GetEnterpriseMachineID(), machine_model, brand_code,
device_management_service,
system_url_loader_factory_for_testing_
? system_url_loader_factory_for_testing_
: g_browser_process->shared_url_loader_factory(),
signing_service_.get(), CloudPolicyClient::DeviceDMTokenCallback());
}
void DeviceCloudPolicyInitializer::TryToCreateClient() {
if (!device_store_->is_initialized() ||
!device_store_->has_policy() ||
state_keys_broker_->pending() ||
enrollment_handler_ ||
install_attributes_->IsActiveDirectoryManaged()) {
return;
}
StartConnection(CreateClient(enterprise_service_));
}
void DeviceCloudPolicyInitializer::StartConnection(
std::unique_ptr<CloudPolicyClient> client) {
if (!manager_->core()->service())
manager_->StartConnection(std::move(client), install_attributes_);
}
bool DeviceCloudPolicyInitializer::GetMachineFlag(const std::string& key,
bool default_value) const {
bool value = default_value;
if (!statistics_provider_->GetMachineFlag(key, &value))
return default_value;
return value;
}
DeviceCloudPolicyInitializer::TpmEnrollmentKeySigningService::
TpmEnrollmentKeySigningService(
cryptohome::AsyncMethodCaller* async_method_caller)
: async_method_caller_(async_method_caller), weak_ptr_factory_(this) {}
DeviceCloudPolicyInitializer::TpmEnrollmentKeySigningService::
~TpmEnrollmentKeySigningService() {}
void DeviceCloudPolicyInitializer::TpmEnrollmentKeySigningService::SignData(
const std::string& data,
const SigningCallback& callback) {
const chromeos::attestation::AttestationCertificateProfile cert_profile =
chromeos::attestation::PROFILE_ENTERPRISE_ENROLLMENT_CERTIFICATE;
const cryptohome::Identification identification;
async_method_caller_->TpmAttestationSignSimpleChallenge(
chromeos::attestation::AttestationFlow::GetKeyTypeForProfile(
cert_profile),
identification,
chromeos::attestation::AttestationFlow::GetKeyNameForProfile(cert_profile,
""),
data, base::Bind(&DeviceCloudPolicyInitializer::
TpmEnrollmentKeySigningService::OnDataSigned,
weak_ptr_factory_.GetWeakPtr(), data, callback));
}
void DeviceCloudPolicyInitializer::TpmEnrollmentKeySigningService::OnDataSigned(
const std::string& data,
const SigningCallback& callback,
bool success,
const std::string& signed_data) {
enterprise_management::SignedData em_signed_data;
chromeos::attestation::SignedData att_signed_data;
if (success && (success = att_signed_data.ParseFromString(signed_data))) {
em_signed_data.set_data(att_signed_data.data());
em_signed_data.set_signature(att_signed_data.signature());
em_signed_data.set_extra_data_bytes(att_signed_data.data().size() -
data.size());
}
callback.Run(success, em_signed_data);
}
} // namespace policy