This source file includes following definitions.
- SampleValidationFailure
- ExtractDomain
- status_
- OnTokenLoaded
- OnDiskCacheLoaded
- CheckLoadFinished
- TranslateLoadResult
- policy_key_loaded_
- Load
- LoadImmediately
- ValidatePolicyForStore
- OnPolicyToStoreValidated
- OnPolicyStored
- OnPolicyRetrieved
- ValidateRetrievedPolicy
- OnRetrievedPolicyValidated
- OnLegacyLoadFinished
- OnLegacyPolicyValidated
- InstallLegacyTokens
- RemoveLegacyCacheDir
- ReloadPolicyKey
- LoadPolicyKey
- OnPolicyKeyReloaded
- EnsurePolicyKeyLoaded
- OnGetSanitizedUsername
#include "chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/file_util.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/sequenced_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/chromeos/policy/user_policy_disk_cache.h"
#include "chrome/browser/chromeos/policy/user_policy_token_loader.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/session_manager_client.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "policy/proto/cloud_policy.pb.h"
#include "policy/proto/device_management_local.pb.h"
namespace em = enterprise_management;
namespace policy {
namespace {
const base::FilePath::CharType kPolicyKeyFile[] =
FILE_PATH_LITERAL("%s/policy.pub");
const size_t kKeySizeLimit = 16 * 1024;
enum ValidationFailure {
VALIDATION_FAILURE_DBUS,
VALIDATION_FAILURE_LOAD_KEY,
VALIDATION_FAILURE_SIZE,
};
void SampleValidationFailure(ValidationFailure sample) {
UMA_HISTOGRAM_ENUMERATION("Enterprise.UserPolicyValidationFailure",
sample,
VALIDATION_FAILURE_SIZE);
}
std::string ExtractDomain(const std::string& username) {
return gaia::ExtractDomainName(gaia::CanonicalizeEmail(username));
}
}
class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate,
public UserPolicyDiskCache::Delegate {
public:
typedef base::Callback<void(const std::string&,
const std::string&,
CloudPolicyStore::Status,
scoped_ptr<em::PolicyFetchResponse>)> Callback;
LegacyPolicyCacheLoader(
const base::FilePath& token_cache_file,
const base::FilePath& policy_cache_file,
scoped_refptr<base::SequencedTaskRunner> background_task_runner);
virtual ~LegacyPolicyCacheLoader();
void Load(const Callback& callback);
virtual void OnTokenLoaded(const std::string& token,
const std::string& device_id) OVERRIDE;
virtual void OnDiskCacheLoaded(
UserPolicyDiskCache::LoadResult result,
const em::CachedCloudPolicyResponse& policy) OVERRIDE;
private:
void CheckLoadFinished();
static CloudPolicyStore::Status TranslateLoadResult(
UserPolicyDiskCache::LoadResult result);
base::WeakPtrFactory<LegacyPolicyCacheLoader> weak_factory_;
scoped_refptr<UserPolicyTokenLoader> token_loader_;
scoped_refptr<UserPolicyDiskCache> policy_cache_;
std::string dm_token_;
std::string device_id_;
bool has_policy_;
scoped_ptr<em::PolicyFetchResponse> policy_;
CloudPolicyStore::Status status_;
Callback callback_;
DISALLOW_COPY_AND_ASSIGN(LegacyPolicyCacheLoader);
};
LegacyPolicyCacheLoader::LegacyPolicyCacheLoader(
const base::FilePath& token_cache_file,
const base::FilePath& policy_cache_file,
scoped_refptr<base::SequencedTaskRunner> background_task_runner)
: weak_factory_(this),
has_policy_(false),
status_(CloudPolicyStore::STATUS_OK) {
token_loader_ = new UserPolicyTokenLoader(weak_factory_.GetWeakPtr(),
token_cache_file,
background_task_runner);
policy_cache_ = new UserPolicyDiskCache(weak_factory_.GetWeakPtr(),
policy_cache_file,
background_task_runner);
}
LegacyPolicyCacheLoader::~LegacyPolicyCacheLoader() {}
void LegacyPolicyCacheLoader::Load(const Callback& callback) {
callback_ = callback;
token_loader_->Load();
policy_cache_->Load();
}
void LegacyPolicyCacheLoader::OnTokenLoaded(const std::string& token,
const std::string& device_id) {
dm_token_ = token;
device_id_ = device_id;
token_loader_ = NULL;
CheckLoadFinished();
}
void LegacyPolicyCacheLoader::OnDiskCacheLoaded(
UserPolicyDiskCache::LoadResult result,
const em::CachedCloudPolicyResponse& policy) {
status_ = TranslateLoadResult(result);
if (result == UserPolicyDiskCache::LOAD_RESULT_SUCCESS) {
if (policy.has_cloud_policy())
policy_.reset(new em::PolicyFetchResponse(policy.cloud_policy()));
} else {
LOG(WARNING) << "Failed to load legacy policy cache: " << result;
}
policy_cache_ = NULL;
CheckLoadFinished();
}
void LegacyPolicyCacheLoader::CheckLoadFinished() {
if (!token_loader_.get() && !policy_cache_.get())
callback_.Run(dm_token_, device_id_, status_, policy_.Pass());
}
CloudPolicyStore::Status LegacyPolicyCacheLoader::TranslateLoadResult(
UserPolicyDiskCache::LoadResult result) {
switch (result) {
case UserPolicyDiskCache::LOAD_RESULT_SUCCESS:
case UserPolicyDiskCache::LOAD_RESULT_NOT_FOUND:
return CloudPolicyStore::STATUS_OK;
case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR:
case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR:
return CloudPolicyStore::STATUS_LOAD_ERROR;
}
NOTREACHED();
return CloudPolicyStore::STATUS_OK;
}
UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
chromeos::CryptohomeClient* cryptohome_client,
chromeos::SessionManagerClient* session_manager_client,
scoped_refptr<base::SequencedTaskRunner> background_task_runner,
const std::string& username,
const base::FilePath& user_policy_key_dir,
const base::FilePath& legacy_token_cache_file,
const base::FilePath& legacy_policy_cache_file)
: UserCloudPolicyStoreBase(background_task_runner),
cryptohome_client_(cryptohome_client),
session_manager_client_(session_manager_client),
username_(username),
user_policy_key_dir_(user_policy_key_dir),
weak_factory_(this),
legacy_cache_dir_(legacy_token_cache_file.DirName()),
legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file,
legacy_policy_cache_file,
background_task_runner)),
legacy_caches_loaded_(false),
policy_key_loaded_(false) {}
UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {}
void UserCloudPolicyStoreChromeOS::Store(
const em::PolicyFetchResponse& policy) {
weak_factory_.InvalidateWeakPtrs();
scoped_ptr<em::PolicyFetchResponse> response(
new em::PolicyFetchResponse(policy));
EnsurePolicyKeyLoaded(
base::Bind(&UserCloudPolicyStoreChromeOS::ValidatePolicyForStore,
weak_factory_.GetWeakPtr(),
base::Passed(&response)));
}
void UserCloudPolicyStoreChromeOS::Load() {
weak_factory_.InvalidateWeakPtrs();
session_manager_client_->RetrievePolicyForUser(
username_,
base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyRetrieved,
weak_factory_.GetWeakPtr()));
}
void UserCloudPolicyStoreChromeOS::LoadImmediately() {
std::string policy_blob =
session_manager_client_->BlockingRetrievePolicyForUser(username_);
if (policy_blob.empty()) {
NotifyStoreLoaded();
return;
}
scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
if (!policy->ParseFromString(policy_blob)) {
status_ = STATUS_PARSE_ERROR;
NotifyStoreError();
return;
}
std::string sanitized_username =
cryptohome_client_->BlockingGetSanitizedUsername(username_);
if (sanitized_username.empty()) {
status_ = STATUS_LOAD_ERROR;
NotifyStoreError();
return;
}
policy_key_path_ = user_policy_key_dir_.Append(
base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
LoadPolicyKey(policy_key_path_, &policy_key_);
policy_key_loaded_ = true;
scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(
policy.Pass(), CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE);
validator->ValidateUsername(username_, true);
const bool allow_rotation = false;
validator->ValidateSignature(
policy_key_,
GetPolicyVerificationKey(),
ExtractDomain(sanitized_username),
allow_rotation);
validator->RunValidation();
OnRetrievedPolicyValidated(validator.get());
}
void UserCloudPolicyStoreChromeOS::ValidatePolicyForStore(
scoped_ptr<em::PolicyFetchResponse> policy) {
scoped_ptr<UserCloudPolicyValidator> validator =
CreateValidator(policy.Pass(),
CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
validator->ValidateUsername(username_, true);
if (policy_key_.empty()) {
validator->ValidateInitialKey(GetPolicyVerificationKey(),
ExtractDomain(username_));
} else {
const bool allow_rotation = true;
validator->ValidateSignature(policy_key_,
GetPolicyVerificationKey(),
ExtractDomain(username_),
allow_rotation);
}
validator.release()->StartValidation(
base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
weak_factory_.GetWeakPtr()));
}
void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
UserCloudPolicyValidator* validator) {
validation_status_ = validator->status();
UMA_HISTOGRAM_ENUMERATION(
"Enterprise.UserPolicyValidationStoreStatus",
validation_status_,
UserCloudPolicyValidator::VALIDATION_STATUS_SIZE);
if (!validator->success()) {
status_ = STATUS_VALIDATION_ERROR;
NotifyStoreError();
return;
}
std::string policy_blob;
if (!validator->policy()->SerializeToString(&policy_blob)) {
status_ = STATUS_SERIALIZE_ERROR;
NotifyStoreError();
return;
}
session_manager_client_->StorePolicyForUser(
username_,
policy_blob,
validator->policy()->new_public_key(),
base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored,
weak_factory_.GetWeakPtr()));
}
void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) {
if (!success) {
status_ = STATUS_STORE_ERROR;
NotifyStoreError();
} else {
ReloadPolicyKey(base::Bind(&UserCloudPolicyStoreChromeOS::Load,
weak_factory_.GetWeakPtr()));
}
}
void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
const std::string& policy_blob) {
if (policy_blob.empty()) {
if (!legacy_caches_loaded_ && legacy_loader_.get()) {
legacy_caches_loaded_ = true;
legacy_loader_->Load(
base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished,
weak_factory_.GetWeakPtr()));
} else {
policy_.reset();
NotifyStoreLoaded();
}
return;
}
legacy_loader_.reset();
scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
if (!policy->ParseFromString(policy_blob)) {
status_ = STATUS_PARSE_ERROR;
NotifyStoreError();
return;
}
EnsurePolicyKeyLoaded(
base::Bind(&UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy,
weak_factory_.GetWeakPtr(),
base::Passed(&policy)));
}
void UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy(
scoped_ptr<em::PolicyFetchResponse> policy) {
scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(
policy.Pass(), CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE);
validator->ValidateUsername(username_, true);
const bool allow_rotation = false;
validator->ValidateSignature(policy_key_,
GetPolicyVerificationKey(),
ExtractDomain(username_),
allow_rotation);
validator.release()->StartValidation(
base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated,
weak_factory_.GetWeakPtr()));
}
void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
UserCloudPolicyValidator* validator) {
validation_status_ = validator->status();
UMA_HISTOGRAM_ENUMERATION(
"Enterprise.UserPolicyValidationLoadStatus",
validation_status_,
UserCloudPolicyValidator::VALIDATION_STATUS_SIZE);
if (!validator->success()) {
status_ = STATUS_VALIDATION_ERROR;
NotifyStoreError();
return;
}
InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
status_ = STATUS_OK;
if (!legacy_cache_dir_.empty()) {
background_task_runner()->PostTask(
FROM_HERE,
base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir,
legacy_cache_dir_));
legacy_cache_dir_.clear();
}
NotifyStoreLoaded();
}
void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished(
const std::string& dm_token,
const std::string& device_id,
Status status,
scoped_ptr<em::PolicyFetchResponse> policy) {
status_ = status;
if (policy.get()) {
scoped_ptr<UserCloudPolicyValidator> validator =
CreateValidator(policy.Pass(),
CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
validator->ValidateUsername(username_, true);
validator.release()->StartValidation(
base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated,
weak_factory_.GetWeakPtr(),
dm_token,
device_id));
} else {
InstallLegacyTokens(dm_token, device_id);
}
}
void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated(
const std::string& dm_token,
const std::string& device_id,
UserCloudPolicyValidator* validator) {
validation_status_ = validator->status();
if (validator->success()) {
status_ = STATUS_OK;
InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
policy_->clear_public_key_version();
} else {
status_ = STATUS_VALIDATION_ERROR;
}
InstallLegacyTokens(dm_token, device_id);
}
void UserCloudPolicyStoreChromeOS::InstallLegacyTokens(
const std::string& dm_token,
const std::string& device_id) {
if (!dm_token.empty() && !device_id.empty()) {
if (!policy_.get())
policy_.reset(new em::PolicyData());
policy_->set_request_token(dm_token);
policy_->set_device_id(device_id);
}
NotifyStoreLoaded();
}
void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(
const base::FilePath& dir) {
if (base::PathExists(dir) && !base::DeleteFile(dir, true))
LOG(ERROR) << "Failed to remove cache dir " << dir.value();
}
void UserCloudPolicyStoreChromeOS::ReloadPolicyKey(
const base::Closure& callback) {
std::string* key = new std::string();
background_task_runner()->PostTaskAndReply(
FROM_HERE,
base::Bind(&UserCloudPolicyStoreChromeOS::LoadPolicyKey,
policy_key_path_,
key),
base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded,
weak_factory_.GetWeakPtr(),
base::Owned(key),
callback));
}
void UserCloudPolicyStoreChromeOS::LoadPolicyKey(const base::FilePath& path,
std::string* key) {
if (!base::PathExists(path)) {
VLOG(1) << "No key at " << path.value();
return;
}
const bool read_success = base::ReadFileToString(path, key, kKeySizeLimit);
if ((read_success && key->length() == 0) ||
(!read_success && key->length() == kKeySizeLimit)) {
LOG(ERROR) << "Key at " << path.value()
<< (read_success ? " is empty." : " exceeds size limit");
key->clear();
} else if (!read_success) {
LOG(ERROR) << "Failed to read key at " << path.value();
}
if (key->empty())
SampleValidationFailure(VALIDATION_FAILURE_LOAD_KEY);
}
void UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded(
std::string* key,
const base::Closure& callback) {
policy_key_ = *key;
policy_key_loaded_ = true;
callback.Run();
}
void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded(
const base::Closure& callback) {
if (policy_key_loaded_) {
callback.Run();
} else {
cryptohome_client_->GetSanitizedUsername(username_,
base::Bind(&UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername,
weak_factory_.GetWeakPtr(),
callback));
}
}
void UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername(
const base::Closure& callback,
chromeos::DBusMethodCallStatus call_status,
const std::string& sanitized_username) {
if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS &&
!sanitized_username.empty()) {
policy_key_path_ = user_policy_key_dir_.Append(
base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
} else {
SampleValidationFailure(VALIDATION_FAILURE_DBUS);
}
ReloadPolicyKey(callback);
}
}