Index: chrome/browser/chromeos/ownership/owner_settings_service.cc |
diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc b/chrome/browser/chromeos/ownership/owner_settings_service.cc |
similarity index 50% |
rename from chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc |
rename to chrome/browser/chromeos/ownership/owner_settings_service.cc |
index 6f04ebbf5160729816c18057aaec8f3a9da57a3c..d9afe65da9b97d6907d8a85a934a6b699e7e89f6 100644 |
--- a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc |
+++ b/chrome/browser/chromeos/ownership/owner_settings_service.cc |
@@ -2,16 +2,14 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h" |
+#include "chrome/browser/chromeos/ownership/owner_settings_service.h" |
#include <string> |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
-#include "base/callback.h" |
#include "base/command_line.h" |
#include "base/prefs/pref_service.h" |
-#include "base/threading/thread_checker.h" |
#include "chrome/browser/chrome_notification_types.h" |
#include "chrome/browser/chromeos/profiles/profile_helper.h" |
#include "chrome/browser/chromeos/settings/cros_settings.h" |
@@ -19,7 +17,6 @@ |
#include "chrome/browser/profiles/profile.h" |
#include "chromeos/dbus/dbus_thread_manager.h" |
#include "chromeos/tpm_token_loader.h" |
-#include "components/ownership/owner_key_util.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" |
@@ -57,12 +54,70 @@ bool IsOwnerInTests(const std::string& user_id) { |
return static_cast<const base::StringValue*>(value)->GetString() == user_id; |
} |
+// 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. |
+ em::PolicyFetchResponse policy_response; |
+ if (!policy->SerializeToString(policy_response.mutable_policy_data())) { |
+ LOG(ERROR) << "Failed to encode policy payload."; |
+ return std::string(); |
+ } |
+ |
+ // Generate the signature. |
+ scoped_ptr<crypto::SignatureCreator> signature_creator( |
+ crypto::SignatureCreator::Create(private_key)); |
+ signature_creator->Update( |
+ reinterpret_cast<const uint8*>(policy_response.policy_data().c_str()), |
+ policy_response.policy_data().size()); |
+ std::vector<uint8> signature_bytes; |
+ std::string policy_blob; |
+ if (!signature_creator->Final(&signature_bytes)) { |
+ LOG(ERROR) << "Failed to create policy signature."; |
+ return std::string(); |
+ } |
+ |
+ policy_response.mutable_policy_data_signature()->assign( |
+ reinterpret_cast<const char*>(vector_as_array(&signature_bytes)), |
+ signature_bytes.size()); |
+ return policy_response.SerializeAsString(); |
+} |
+ |
void LoadPrivateKeyByPublicKey( |
const scoped_refptr<OwnerKeyUtil>& owner_key_util, |
scoped_refptr<PublicKey> public_key, |
const std::string& username_hash, |
- const base::Callback<void(const scoped_refptr<PublicKey>& public_key, |
- const scoped_refptr<PrivateKey>& private_key)>& |
+ const base::Callback<void(scoped_refptr<PublicKey> public_key, |
+ scoped_refptr<PrivateKey> private_key)>& |
callback) { |
crypto::EnsureNSSInit(); |
crypto::ScopedPK11Slot slot = |
@@ -74,12 +129,11 @@ void LoadPrivateKeyByPublicKey( |
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(const scoped_refptr<PublicKey>& public_key, |
- const scoped_refptr<PrivateKey>& private_key)>& |
- callback) { |
+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)) { |
@@ -121,14 +175,15 @@ bool DoesPrivateKeyExistAsyncHelper( |
// not. Responds via |callback|. |
void DoesPrivateKeyExistAsync( |
const scoped_refptr<OwnerKeyUtil>& owner_key_util, |
- const OwnerSettingsServiceChromeOS::IsOwnerCallback& callback) { |
+ const OwnerSettingsService::IsOwnerCallback& callback) { |
if (!owner_key_util) { |
callback.Run(false); |
return; |
} |
scoped_refptr<base::TaskRunner> task_runner = |
- BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( |
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
+ content::BrowserThread::GetBlockingPool() |
+ ->GetTaskRunnerWithShutdownBehavior( |
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
base::PostTaskAndReplyWithResult( |
task_runner.get(), |
FROM_HERE, |
@@ -136,28 +191,60 @@ void DoesPrivateKeyExistAsync( |
callback); |
} |
-DeviceSettingsService* GetDeviceSettingsService() { |
- if (g_device_settings_service_for_testing) |
- return g_device_settings_service_for_testing; |
- return DeviceSettingsService::IsInitialized() ? DeviceSettingsService::Get() |
- : NULL; |
+// 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 |
-OwnerSettingsServiceChromeOS::OwnerSettingsServiceChromeOS( |
+OwnerSettingsService::OwnerSettingsService( |
Profile* profile, |
const scoped_refptr<OwnerKeyUtil>& owner_key_util) |
- : ownership::OwnerSettingsService(owner_key_util), |
- profile_(profile), |
+ : profile_(profile), |
+ owner_key_util_(owner_key_util), |
waiting_for_profile_creation_(true), |
waiting_for_tpm_token_(true), |
weak_factory_(this) { |
if (TPMTokenLoader::IsInitialized()) { |
TPMTokenLoader::TPMTokenStatus tpm_token_status = |
TPMTokenLoader::Get()->IsTPMTokenEnabled( |
- base::Bind(&OwnerSettingsServiceChromeOS::OnTPMTokenReady, |
- weak_factory_.GetWeakPtr())); |
+ base::Bind(&OwnerSettingsService::OnTPMTokenReady, as_weak_ptr())); |
waiting_for_tpm_token_ = |
tpm_token_status == TPMTokenLoader::TPM_TOKEN_STATUS_UNDETERMINED; |
} |
@@ -172,7 +259,7 @@ OwnerSettingsServiceChromeOS::OwnerSettingsServiceChromeOS( |
content::Source<Profile>(profile_)); |
} |
-OwnerSettingsServiceChromeOS::~OwnerSettingsServiceChromeOS() { |
+OwnerSettingsService::~OwnerSettingsService() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
if (DBusThreadManager::IsInitialized() && |
DBusThreadManager::Get()->GetSessionManagerClient()) { |
@@ -180,32 +267,80 @@ OwnerSettingsServiceChromeOS::~OwnerSettingsServiceChromeOS() { |
} |
} |
-void OwnerSettingsServiceChromeOS::OnTPMTokenReady( |
- bool /* tpm_token_enabled */) { |
+bool OwnerSettingsService::IsOwner() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- waiting_for_tpm_token_ = false; |
+ return private_key_ && private_key_->key(); |
+} |
- // TPMTokenLoader initializes the TPM and NSS database which is necessary to |
- // determine ownership. Force a reload once we know these are initialized. |
- ReloadKeypair(); |
+void OwnerSettingsService::IsOwnerAsync(const IsOwnerCallback& callback) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (private_key_) { |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ base::Bind(callback, IsOwner())); |
+ } else { |
+ pending_is_owner_callbacks_.push_back(callback); |
+ } |
} |
-void OwnerSettingsServiceChromeOS::SignAndStorePolicyAsync( |
+bool OwnerSettingsService::AssembleAndSignPolicyAsync( |
scoped_ptr<em::PolicyData> policy, |
+ const AssembleAndSignPolicyCallback& callback) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (!IsOwner()) |
+ return false; |
+ base::PostTaskAndReplyWithResult( |
+ BrowserThread::GetBlockingPool(), |
+ FROM_HERE, |
+ base::Bind( |
+ &AssembleAndSignPolicy, base::Passed(&policy), private_key_->key()), |
+ callback); |
+ return true; |
+} |
+ |
+void OwnerSettingsService::SignAndStoreAsync( |
+ scoped_ptr<em::ChromeDeviceSettingsProto> settings, |
const base::Closure& callback) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- SignAndStoreSettingsOperation* operation = new SignAndStoreSettingsOperation( |
- base::Bind(&OwnerSettingsServiceChromeOS::HandleCompletedOperation, |
- weak_factory_.GetWeakPtr(), |
- callback), |
- policy.Pass()); |
- operation->set_owner_settings_service(weak_factory_.GetWeakPtr()); |
- pending_operations_.push_back(operation); |
- if (pending_operations_.front() == operation) |
- StartNextOperation(); |
+ 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 OwnerSettingsServiceChromeOS::Observe( |
+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, |
const content::NotificationDetails& details) { |
@@ -222,17 +357,26 @@ void OwnerSettingsServiceChromeOS::Observe( |
} |
waiting_for_profile_creation_ = false; |
- ReloadKeypair(); |
+ ReloadPrivateKey(); |
} |
-void OwnerSettingsServiceChromeOS::OwnerKeySet(bool success) { |
+void OwnerSettingsService::OnTPMTokenReady(bool /* unused token_enabled */) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ waiting_for_tpm_token_ = false; |
+ |
+ // TPMTokenLoader initializes the TPM and NSS database which is necessary to |
+ // determine ownership. Force a reload once we know these are initialized. |
+ ReloadPrivateKey(); |
+} |
+ |
+void OwnerSettingsService::OwnerKeySet(bool success) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
if (success) |
- ReloadKeypair(); |
+ ReloadPrivateKey(); |
} |
// static |
-void OwnerSettingsServiceChromeOS::IsOwnerForSafeModeAsync( |
+void OwnerSettingsService::IsOwnerForSafeModeAsync( |
const std::string& user_hash, |
const scoped_refptr<OwnerKeyUtil>& owner_key_util, |
const IsOwnerCallback& callback) { |
@@ -250,49 +394,74 @@ void OwnerSettingsServiceChromeOS::IsOwnerForSafeModeAsync( |
} |
// static |
-void OwnerSettingsServiceChromeOS::SetDeviceSettingsServiceForTesting( |
+void OwnerSettingsService::SetDeviceSettingsServiceForTesting( |
DeviceSettingsService* device_settings_service) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
g_device_settings_service_for_testing = device_settings_service; |
} |
-void OwnerSettingsServiceChromeOS::OnPostKeypairLoadedActions() { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- |
- user_id_ = profile_->GetProfileName(); |
- const bool is_owner = IsOwner() || IsOwnerInTests(user_id_); |
- if (is_owner && GetDeviceSettingsService()) |
- GetDeviceSettingsService()->InitOwner(user_id_, weak_factory_.GetWeakPtr()); |
-} |
- |
-void OwnerSettingsServiceChromeOS::ReloadKeypairImpl(const base::Callback< |
- void(const scoped_refptr<PublicKey>& public_key, |
- const scoped_refptr<PrivateKey>& private_key)>& callback) { |
+void OwnerSettingsService::ReloadPrivateKey() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- |
if (waiting_for_profile_creation_ || waiting_for_tpm_token_) |
return; |
scoped_refptr<base::TaskRunner> task_runner = |
- BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( |
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
+ content::BrowserThread::GetBlockingPool() |
+ ->GetTaskRunnerWithShutdownBehavior( |
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
task_runner->PostTask( |
FROM_HERE, |
base::Bind(&LoadPrivateKey, |
- owner_key_util_, |
+ GetOwnerKeyUtil(), |
ProfileHelper::GetUserIdHashFromProfile(profile_), |
- callback)); |
+ base::Bind(&OwnerSettingsService::OnPrivateKeyLoaded, |
+ weak_factory_.GetWeakPtr()))); |
} |
-void OwnerSettingsServiceChromeOS::StartNextOperation() { |
+void OwnerSettingsService::OnPrivateKeyLoaded( |
+ scoped_refptr<PublicKey> public_key, |
+ scoped_refptr<PrivateKey> private_key) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ public_key_ = public_key; |
+ private_key_ = private_key; |
+ |
+ user_id_ = profile_->GetProfileName(); |
+ const bool is_owner = IsOwner() || IsOwnerInTests(user_id_); |
+ if (is_owner && GetDeviceSettingsService()) |
+ GetDeviceSettingsService()->InitOwner(user_id_, weak_factory_.GetWeakPtr()); |
+ |
+ std::vector<IsOwnerCallback> is_owner_callbacks; |
+ is_owner_callbacks.swap(pending_is_owner_callbacks_); |
+ for (std::vector<IsOwnerCallback>::iterator it(is_owner_callbacks.begin()); |
+ it != is_owner_callbacks.end(); |
+ ++it) { |
+ it->Run(is_owner); |
+ } |
+} |
+ |
+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(), owner_key_util_, public_key_); |
+ service->session_manager_client(), GetOwnerKeyUtil(), public_key_); |
} |
} |
-void OwnerSettingsServiceChromeOS::HandleCompletedOperation( |
+void OwnerSettingsService::HandleCompletedOperation( |
const base::Closure& callback, |
SessionManagerOperation* operation, |
DeviceSettingsService::Status status) { |
@@ -308,10 +477,10 @@ void OwnerSettingsServiceChromeOS::HandleCompletedOperation( |
(operation->public_key() && public_key_ && |
operation->public_key()->data() != public_key_->data())) { |
// Public part changed so we need to reload private part too. |
- ReloadKeypair(); |
+ ReloadPrivateKey(); |
content::NotificationService::current()->Notify( |
chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED, |
- content::Source<OwnerSettingsServiceChromeOS>(this), |
+ content::Source<OwnerSettingsService>(this), |
content::NotificationService::NoDetails()); |
} |
service->OnSignAndStoreOperationCompleted(status); |
@@ -323,4 +492,26 @@ void OwnerSettingsServiceChromeOS::HandleCompletedOperation( |
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()); |
+ return owner_key_util_; |
+} |
+ |
+DeviceSettingsService* OwnerSettingsService::GetDeviceSettingsService() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (g_device_settings_service_for_testing) |
+ return g_device_settings_service_for_testing; |
+ if (DeviceSettingsService::IsInitialized()) |
+ return DeviceSettingsService::Get(); |
+ return NULL; |
+} |
+ |
} // namespace chromeos |