| Index: chrome/browser/chromeos/ownership/owner_settings_service.cc
|
| diff --git a/chrome/browser/chromeos/ownership/owner_settings_service.cc b/chrome/browser/chromeos/ownership/owner_settings_service.cc
|
| index 81724dfb887ed1dcf76482b5f17df6cd3b9f366d..893c656020072ba704e4aed6f9cf70b4f685fc84 100644
|
| --- a/chrome/browser/chromeos/ownership/owner_settings_service.cc
|
| +++ b/chrome/browser/chromeos/ownership/owner_settings_service.cc
|
| @@ -13,9 +13,12 @@
|
| #include "chrome/browser/chromeos/login/users/user_manager.h"
|
| #include "chrome/browser/chromeos/ownership/owner_settings_service_factory.h"
|
| #include "chrome/browser/chromeos/profiles/profile_helper.h"
|
| +#include "chrome/browser/chromeos/settings/session_manager_operation.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| +#include "components/policy/core/common/cloud/cloud_policy_constants.h"
|
| #include "content/public/browser/browser_thread.h"
|
| #include "content/public/browser/notification_details.h"
|
| +#include "content/public/browser/notification_service.h"
|
| #include "content/public/browser/notification_source.h"
|
| #include "crypto/nss_util.h"
|
| #include "crypto/nss_util_internal.h"
|
| @@ -34,6 +37,36 @@ namespace {
|
| scoped_refptr<OwnerKeyUtil>* g_owner_key_util_for_testing = NULL;
|
| DeviceSettingsService* g_device_settings_service_for_testing = NULL;
|
|
|
| +// Assembles PolicyData based on |settings|, |policy_data| and
|
| +// |user_id|.
|
| +scoped_ptr<em::PolicyData> AssemblePolicy(
|
| + const std::string& user_id,
|
| + const em::PolicyData* policy_data,
|
| + const em::ChromeDeviceSettingsProto* settings) {
|
| + scoped_ptr<em::PolicyData> policy(new em::PolicyData());
|
| + if (policy_data) {
|
| + // Preserve management settings.
|
| + if (policy_data->has_management_mode())
|
| + policy->set_management_mode(policy_data->management_mode());
|
| + if (policy_data->has_request_token())
|
| + policy->set_request_token(policy_data->request_token());
|
| + if (policy_data->has_device_id())
|
| + policy->set_device_id(policy_data->device_id());
|
| + } else {
|
| + // If there's no previous policy data, this is the first time the device
|
| + // setting is set. We set the management mode to NOT_MANAGED initially.
|
| + policy->set_management_mode(em::PolicyData::NOT_MANAGED);
|
| + }
|
| + policy->set_policy_type(policy::dm_protocol::kChromeDevicePolicyType);
|
| + policy->set_timestamp(
|
| + (base::Time::Now() - base::Time::UnixEpoch()).InMilliseconds());
|
| + policy->set_username(user_id);
|
| + if (!settings->SerializeToString(policy->mutable_policy_value()))
|
| + return scoped_ptr<em::PolicyData>();
|
| +
|
| + return policy.Pass();
|
| +}
|
| +
|
| std::string AssembleAndSignPolicy(scoped_ptr<em::PolicyData> policy,
|
| crypto::RSAPrivateKey* private_key) {
|
| // Assemble the policy.
|
| @@ -64,30 +97,37 @@ std::string AssembleAndSignPolicy(scoped_ptr<em::PolicyData> policy,
|
|
|
| void LoadPrivateKeyByPublicKey(
|
| const scoped_refptr<OwnerKeyUtil>& owner_key_util,
|
| - const std::vector<uint8>& public_key,
|
| + scoped_refptr<PublicKey> public_key,
|
| const std::string& username_hash,
|
| - const base::Callback<void(scoped_ptr<crypto::RSAPrivateKey>)>& callback) {
|
| + const base::Callback<void(scoped_refptr<PublicKey> public_key,
|
| + scoped_refptr<PrivateKey> private_key)>&
|
| + callback) {
|
| crypto::EnsureNSSInit();
|
| crypto::ScopedPK11Slot slot =
|
| crypto::GetPublicSlotForChromeOSUser(username_hash);
|
| - scoped_ptr<crypto::RSAPrivateKey> key(
|
| - owner_key_util->FindPrivateKeyInSlot(public_key, slot.get()));
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE, base::Bind(callback, base::Passed(&key)));
|
| + scoped_refptr<PrivateKey> private_key(new PrivateKey(
|
| + owner_key_util->FindPrivateKeyInSlot(public_key->data(), slot.get())));
|
| + BrowserThread::PostTask(BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(callback, public_key, private_key));
|
| }
|
|
|
| -void LoadPrivateKey(
|
| - const scoped_refptr<OwnerKeyUtil>& owner_key_util,
|
| - const std::string username_hash,
|
| - const base::Callback<void(scoped_ptr<crypto::RSAPrivateKey>)>& callback) {
|
| - std::vector<uint8> public_key;
|
| - if (!owner_key_util->ImportPublicKey(&public_key)) {
|
| - scoped_ptr<crypto::RSAPrivateKey> result;
|
| +void LoadPrivateKey(const scoped_refptr<OwnerKeyUtil>& owner_key_util,
|
| + const std::string username_hash,
|
| + const base::Callback<void(
|
| + scoped_refptr<PublicKey> public_key,
|
| + scoped_refptr<PrivateKey> private_key)>& callback) {
|
| + std::vector<uint8> public_key_data;
|
| + scoped_refptr<PublicKey> public_key;
|
| + if (!owner_key_util->ImportPublicKey(&public_key_data)) {
|
| + scoped_refptr<PrivateKey> private_key;
|
| BrowserThread::PostTask(BrowserThread::UI,
|
| FROM_HERE,
|
| - base::Bind(callback, base::Passed(&result)));
|
| + base::Bind(callback, public_key, private_key));
|
| return;
|
| }
|
| + public_key = new PublicKey();
|
| + public_key->data().swap(public_key_data);
|
| bool rv = BrowserThread::PostTask(BrowserThread::IO,
|
| FROM_HERE,
|
| base::Bind(&LoadPrivateKeyByPublicKey,
|
| @@ -134,6 +174,46 @@ void DoesPrivateKeyExistAsync(
|
| callback);
|
| }
|
|
|
| +// Returns the current management mode.
|
| +em::PolicyData::ManagementMode GetManagementMode(
|
| + DeviceSettingsService* service) {
|
| + if (!service) {
|
| + LOG(ERROR) << "DeviceSettingsService is not initialized";
|
| + return em::PolicyData::NOT_MANAGED;
|
| + }
|
| +
|
| + const em::PolicyData* policy_data = service->policy_data();
|
| + if (policy_data && policy_data->has_management_mode())
|
| + return policy_data->management_mode();
|
| + return em::PolicyData::NOT_MANAGED;
|
| +}
|
| +
|
| +// Returns true if it is okay to transfer from the current mode to the new
|
| +// mode. This function should be called in SetManagementMode().
|
| +bool CheckManagementModeTransition(em::PolicyData::ManagementMode current_mode,
|
| + em::PolicyData::ManagementMode new_mode) {
|
| + // Mode is not changed.
|
| + if (current_mode == new_mode)
|
| + return true;
|
| +
|
| + switch (current_mode) {
|
| + case em::PolicyData::NOT_MANAGED:
|
| + // For consumer management enrollment.
|
| + return new_mode == em::PolicyData::CONSUMER_MANAGED;
|
| +
|
| + case em::PolicyData::ENTERPRISE_MANAGED:
|
| + // Management mode cannot be set when it is currently ENTERPRISE_MANAGED.
|
| + return false;
|
| +
|
| + case em::PolicyData::CONSUMER_MANAGED:
|
| + // For consumer management unenrollment.
|
| + return new_mode == em::PolicyData::NOT_MANAGED;
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return false;
|
| +}
|
| +
|
| } // namespace
|
|
|
| OwnerSettingsService::OwnerSettingsService(Profile* profile)
|
| @@ -174,7 +254,7 @@ void OwnerSettingsService::IsOwnerAsync(const IsOwnerCallback& callback) {
|
| }
|
|
|
| bool OwnerSettingsService::AssembleAndSignPolicyAsync(
|
| - scoped_ptr<enterprise_management::PolicyData> policy,
|
| + scoped_ptr<em::PolicyData> policy,
|
| const AssembleAndSignPolicyCallback& callback) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| if (!IsOwner())
|
| @@ -188,6 +268,49 @@ bool OwnerSettingsService::AssembleAndSignPolicyAsync(
|
| return true;
|
| }
|
|
|
| +void OwnerSettingsService::SignAndStoreAsync(
|
| + scoped_ptr<em::ChromeDeviceSettingsProto> settings,
|
| + const base::Closure& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + scoped_ptr<em::PolicyData> policy = AssemblePolicy(
|
| + user_id_, GetDeviceSettingsService()->policy_data(), settings.get());
|
| + if (!policy) {
|
| + HandleError(DeviceSettingsService::STORE_POLICY_ERROR, callback);
|
| + return;
|
| + }
|
| +
|
| + EnqueueSignAndStore(policy.Pass(), callback);
|
| +}
|
| +
|
| +void OwnerSettingsService::SetManagementSettingsAsync(
|
| + em::PolicyData::ManagementMode management_mode,
|
| + const std::string& request_token,
|
| + const std::string& device_id,
|
| + const base::Closure& callback) {
|
| + em::PolicyData::ManagementMode current_mode =
|
| + GetManagementMode(GetDeviceSettingsService());
|
| + if (!CheckManagementModeTransition(current_mode, management_mode)) {
|
| + LOG(ERROR) << "Invalid management mode transition: current mode = "
|
| + << current_mode << ", new mode = " << management_mode;
|
| + HandleError(DeviceSettingsService::STORE_POLICY_ERROR, callback);
|
| + return;
|
| + }
|
| +
|
| + DeviceSettingsService* service = GetDeviceSettingsService();
|
| + scoped_ptr<em::PolicyData> policy = AssemblePolicy(
|
| + user_id_, service->policy_data(), service->device_settings());
|
| + if (!policy) {
|
| + HandleError(DeviceSettingsService::STORE_POLICY_ERROR, callback);
|
| + return;
|
| + }
|
| +
|
| + policy->set_management_mode(management_mode);
|
| + policy->set_request_token(request_token);
|
| + policy->set_device_id(device_id);
|
| +
|
| + EnqueueSignAndStore(policy.Pass(), callback);
|
| +}
|
| +
|
| void OwnerSettingsService::Observe(
|
| int type,
|
| const content::NotificationSource& source,
|
| @@ -275,13 +398,15 @@ void OwnerSettingsService::ReloadPrivateKey() {
|
| }
|
|
|
| void OwnerSettingsService::OnPrivateKeyLoaded(
|
| - scoped_ptr<crypto::RSAPrivateKey> private_key) {
|
| + scoped_refptr<PublicKey> public_key,
|
| + scoped_refptr<PrivateKey> private_key) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - private_key_ = new PrivateKey(private_key.release());
|
| + public_key_ = public_key;
|
| + private_key_ = private_key;
|
|
|
| - const std::string& user_id = profile_->GetProfileName();
|
| - if (user_id == OwnerSettingsServiceFactory::GetInstance()->GetUsername())
|
| - GetDeviceSettingsService()->InitOwner(user_id, weak_factory_.GetWeakPtr());
|
| + user_id_ = profile_->GetProfileName();
|
| + if (user_id_ == OwnerSettingsServiceFactory::GetInstance()->GetUsername())
|
| + GetDeviceSettingsService()->InitOwner(user_id_, weak_factory_.GetWeakPtr());
|
|
|
| std::vector<IsOwnerCallback> is_owner_callbacks;
|
| is_owner_callbacks.swap(pending_is_owner_callbacks_);
|
| @@ -293,6 +418,68 @@ void OwnerSettingsService::OnPrivateKeyLoaded(
|
| }
|
| }
|
|
|
| +void OwnerSettingsService::EnqueueSignAndStore(
|
| + scoped_ptr<em::PolicyData> policy,
|
| + const base::Closure& callback) {
|
| + SignAndStoreSettingsOperation* operation = new SignAndStoreSettingsOperation(
|
| + base::Bind(&OwnerSettingsService::HandleCompletedOperation,
|
| + weak_factory_.GetWeakPtr(),
|
| + callback),
|
| + policy.Pass());
|
| + operation->set_delegate(weak_factory_.GetWeakPtr());
|
| + pending_operations_.push_back(operation);
|
| + if (pending_operations_.front() == operation)
|
| + StartNextOperation();
|
| +}
|
| +
|
| +void OwnerSettingsService::StartNextOperation() {
|
| + DeviceSettingsService* service = GetDeviceSettingsService();
|
| + if (!pending_operations_.empty() && service &&
|
| + service->session_manager_client()) {
|
| + pending_operations_.front()->Start(
|
| + service->session_manager_client(), GetOwnerKeyUtil(), public_key_);
|
| + }
|
| +}
|
| +
|
| +void OwnerSettingsService::HandleCompletedOperation(
|
| + const base::Closure& callback,
|
| + SessionManagerOperation* operation,
|
| + DeviceSettingsService::Status status) {
|
| + DCHECK_EQ(operation, pending_operations_.front());
|
| +
|
| + DeviceSettingsService* service = GetDeviceSettingsService();
|
| + if (status == DeviceSettingsService::STORE_SUCCESS) {
|
| + service->set_policy_data(operation->policy_data().Pass());
|
| + service->set_device_settings(operation->device_settings().Pass());
|
| + }
|
| +
|
| + if ((operation->public_key() && !public_key_) ||
|
| + (operation->public_key() && public_key_ &&
|
| + operation->public_key()->data() != public_key_->data())) {
|
| + // Public part changed so we need to reload private part too.
|
| + ReloadPrivateKey();
|
| + content::NotificationService::current()->Notify(
|
| + chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
|
| + content::Source<OwnerSettingsService>(this),
|
| + content::NotificationService::NoDetails());
|
| + }
|
| + service->OnSignAndStoreOperationCompleted(status);
|
| + if (!callback.is_null())
|
| + callback.Run();
|
| +
|
| + pending_operations_.pop_front();
|
| + delete operation;
|
| + StartNextOperation();
|
| +}
|
| +
|
| +void OwnerSettingsService::HandleError(DeviceSettingsService::Status status,
|
| + const base::Closure& callback) {
|
| + LOG(ERROR) << "Session manager operation failed: " << status;
|
| + GetDeviceSettingsService()->OnSignAndStoreOperationCompleted(status);
|
| + if (!callback.is_null())
|
| + callback.Run();
|
| +}
|
| +
|
| scoped_refptr<OwnerKeyUtil> OwnerSettingsService::GetOwnerKeyUtil() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| if (g_owner_key_util_for_testing)
|
|
|