blob: 3e6764b13c830a86ed8671b229a0be92b162610a [file] [log] [blame]
// Copyright (c) 2012 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/ash/policy/core/device_local_account_policy_store.h"
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "chrome/browser/chromeos/policy/value_validation/onc_user_policy_value_validator.h"
#include "components/ownership/owner_key_util.h"
#include "components/policy/core/common/cloud/device_management_service.h"
#include "components/policy/core/common/external_data_fetcher.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/proto/cloud_policy.pb.h"
#include "components/policy/proto/device_management_backend.pb.h"
using RetrievePolicyResponseType =
chromeos::SessionManagerClient::RetrievePolicyResponseType;
namespace em = enterprise_management;
namespace policy {
DeviceLocalAccountPolicyStore::DeviceLocalAccountPolicyStore(
const std::string& account_id,
chromeos::SessionManagerClient* session_manager_client,
ash::DeviceSettingsService* device_settings_service,
scoped_refptr<base::SequencedTaskRunner> background_task_runner)
: UserCloudPolicyStoreBase(background_task_runner,
PolicyScope::POLICY_SCOPE_USER,
PolicySource::POLICY_SOURCE_CLOUD),
account_id_(account_id),
session_manager_client_(session_manager_client),
device_settings_service_(device_settings_service) {}
DeviceLocalAccountPolicyStore::~DeviceLocalAccountPolicyStore() {}
void DeviceLocalAccountPolicyStore::Load() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Cancel all pending requests.
weak_factory_.InvalidateWeakPtrs();
session_manager_client_->RetrieveDeviceLocalAccountPolicy(
account_id_,
base::BindOnce(&DeviceLocalAccountPolicyStore::ValidateLoadedPolicyBlob,
weak_factory_.GetWeakPtr(),
true /*validate_in_background*/));
}
std::unique_ptr<UserCloudPolicyValidator>
DeviceLocalAccountPolicyStore::CreateValidator(
std::unique_ptr<em::PolicyFetchResponse> policy,
CloudPolicyValidatorBase::ValidateTimestampOption option) {
auto validator =
UserCloudPolicyStoreBase::CreateValidator(std::move(policy), option);
validator->ValidateValues(std::make_unique<ONCUserPolicyValueValidator>());
return validator;
}
void DeviceLocalAccountPolicyStore::LoadImmediately() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This blocking D-Bus call is in the startup path and will block the UI
// thread. This only happens when the Profile is created synchronously, which
// on Chrome OS happens whenever the browser is restarted into the same
// session, that is when the browser crashes, or right after signin if
// the user has flags configured in about:flags.
// However, on those paths we must load policy synchronously so that the
// Profile initialization never sees unmanaged prefs, which would lead to
// data loss. http://crbug.com/263061
// Cancel all running async loads.
weak_factory_.InvalidateWeakPtrs();
std::string policy_blob;
RetrievePolicyResponseType response =
session_manager_client_->BlockingRetrieveDeviceLocalAccountPolicy(
account_id_, &policy_blob);
ValidateLoadedPolicyBlob(false /*validate_in_background*/, response,
policy_blob);
}
void DeviceLocalAccountPolicyStore::Store(
const em::PolicyFetchResponse& policy) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Cancel all pending requests.
weak_factory_.InvalidateWeakPtrs();
CheckKeyAndValidate(
true, std::make_unique<em::PolicyFetchResponse>(policy),
true /*validate_in_background*/,
base::BindOnce(&DeviceLocalAccountPolicyStore::OnPolicyToStoreValidated,
weak_factory_.GetWeakPtr()));
}
void DeviceLocalAccountPolicyStore::ValidateLoadedPolicyBlob(
bool validate_in_background,
RetrievePolicyResponseType response_type,
const std::string& policy_blob) {
if (response_type != RetrievePolicyResponseType::SUCCESS ||
policy_blob.empty()) {
status_ = CloudPolicyStore::STATUS_LOAD_ERROR;
NotifyStoreError();
} else {
std::unique_ptr<em::PolicyFetchResponse> policy(
new em::PolicyFetchResponse());
if (policy->ParseFromString(policy_blob)) {
CheckKeyAndValidate(
false, std::move(policy), validate_in_background,
base::BindOnce(&DeviceLocalAccountPolicyStore::UpdatePolicy,
weak_factory_.GetWeakPtr()));
} else {
status_ = CloudPolicyStore::STATUS_PARSE_ERROR;
NotifyStoreError();
}
}
}
void DeviceLocalAccountPolicyStore::UpdatePolicy(
const std::string& signature_validation_public_key,
UserCloudPolicyValidator* validator) {
DCHECK(!signature_validation_public_key.empty());
validation_result_ = validator->GetValidationResult();
if (!validator->success()) {
status_ = STATUS_VALIDATION_ERROR;
NotifyStoreError();
return;
}
policy_fetch_response_ = std::move(validator->policy());
InstallPolicy(std::move(validator->policy_data()),
std::move(validator->payload()),
signature_validation_public_key);
status_ = STATUS_OK;
NotifyStoreLoaded();
}
void DeviceLocalAccountPolicyStore::OnPolicyToStoreValidated(
const std::string& signature_validation_public_key_unused,
UserCloudPolicyValidator* validator) {
validation_result_ = validator->GetValidationResult();
if (!validator->success()) {
status_ = STATUS_VALIDATION_ERROR;
NotifyStoreError();
return;
}
std::string policy_blob;
if (!validator->policy()->SerializeToString(&policy_blob)) {
status_ = CloudPolicyStore::STATUS_SERIALIZE_ERROR;
NotifyStoreError();
return;
}
session_manager_client_->StoreDeviceLocalAccountPolicy(
account_id_, policy_blob,
base::BindOnce(&DeviceLocalAccountPolicyStore::HandleStoreResult,
weak_factory_.GetWeakPtr()));
}
void DeviceLocalAccountPolicyStore::HandleStoreResult(bool success) {
if (!success) {
status_ = CloudPolicyStore::STATUS_STORE_ERROR;
NotifyStoreError();
} else {
Load();
}
}
void DeviceLocalAccountPolicyStore::CheckKeyAndValidate(
bool valid_timestamp_required,
std::unique_ptr<em::PolicyFetchResponse> policy,
bool validate_in_background,
ValidateCompletionCallback callback) {
if (validate_in_background) {
device_settings_service_->GetOwnershipStatusAsync(base::BindOnce(
&DeviceLocalAccountPolicyStore::Validate, weak_factory_.GetWeakPtr(),
valid_timestamp_required, std::move(policy), std::move(callback),
validate_in_background));
} else {
ash::DeviceSettingsService::OwnershipStatus ownership_status =
device_settings_service_->GetOwnershipStatus();
Validate(valid_timestamp_required, std::move(policy), std::move(callback),
validate_in_background, ownership_status);
}
}
void DeviceLocalAccountPolicyStore::Validate(
bool valid_timestamp_required,
std::unique_ptr<em::PolicyFetchResponse> policy_response,
ValidateCompletionCallback callback,
bool validate_in_background,
ash::DeviceSettingsService::OwnershipStatus ownership_status) {
DCHECK_NE(ash::DeviceSettingsService::OWNERSHIP_UNKNOWN, ownership_status);
const em::PolicyData* device_policy_data =
device_settings_service_->policy_data();
// Note that the key is obtained through the device settings service instead
// of using |policy_signature_public_key_| member, as the latter one is
// updated only after the successful installation of the policy.
scoped_refptr<ownership::PublicKey> key =
device_settings_service_->GetPublicKey();
if (!key.get() || !key->is_loaded() || !device_policy_data) {
LOG(ERROR) << "Failed policy validation, key: " << (key.get() != nullptr)
<< ", is_loaded: " << (key.get() ? key->is_loaded() : false)
<< ", device_policy_data: " << (device_policy_data != nullptr);
status_ = CloudPolicyStore::STATUS_BAD_STATE;
NotifyStoreLoaded();
return;
}
auto validator = std::make_unique<UserCloudPolicyValidator>(
std::move(policy_response), background_task_runner());
validator->ValidateUsername(account_id_);
validator->ValidatePolicyType(dm_protocol::kChromePublicAccountPolicyType);
// The timestamp is verified when storing a new policy downloaded from the
// server but not when loading a cached policy from disk.
// See SessionManagerOperation::ValidateDeviceSettings for the rationale.
validator->ValidateAgainstCurrentPolicy(
policy(),
valid_timestamp_required
? CloudPolicyValidatorBase::TIMESTAMP_VALIDATED
: CloudPolicyValidatorBase::TIMESTAMP_NOT_VALIDATED,
CloudPolicyValidatorBase::DM_TOKEN_NOT_REQUIRED,
CloudPolicyValidatorBase::DEVICE_ID_NOT_REQUIRED);
// Validate the DMToken to match what device policy has.
validator->ValidateDMToken(device_policy_data->request_token(),
CloudPolicyValidatorBase::DM_TOKEN_REQUIRED);
// Validate the device id to match what device policy has.
validator->ValidateDeviceId(device_policy_data->device_id(),
CloudPolicyValidatorBase::DEVICE_ID_REQUIRED);
validator->ValidatePayload();
validator->ValidateSignature(key->as_string());
if (validate_in_background) {
UserCloudPolicyValidator::StartValidation(
std::move(validator),
base::BindOnce(std::move(callback), key->as_string()));
} else {
validator->RunValidation();
UpdatePolicy(key->as_string(), validator.get());
}
}
} // namespace policy