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) |