Index: chrome/browser/policy/user_cloud_policy_store_chromeos.cc |
diff --git a/chrome/browser/policy/user_cloud_policy_store_chromeos.cc b/chrome/browser/policy/user_cloud_policy_store_chromeos.cc |
index 419a3f2d497dab9aaf5f9687b85a4c59767a5a49..803ea9a48197b4f8037a200262ddc5bc32c5ae2a 100644 |
--- a/chrome/browser/policy/user_cloud_policy_store_chromeos.cc |
+++ b/chrome/browser/policy/user_cloud_policy_store_chromeos.cc |
@@ -11,10 +11,13 @@ |
#include "base/callback.h" |
#include "base/file_util.h" |
#include "base/memory/ref_counted.h" |
+#include "base/stringprintf.h" |
#include "chrome/browser/policy/proto/cloud_policy.pb.h" |
#include "chrome/browser/policy/proto/device_management_local.pb.h" |
#include "chrome/browser/policy/user_policy_disk_cache.h" |
+#include "chrome/browser/policy/user_policy_key.h" |
#include "chrome/browser/policy/user_policy_token_loader.h" |
+#include "chromeos/dbus/cryptohome_client.h" |
#include "chromeos/dbus/session_manager_client.h" |
#include "content/public/browser/browser_thread.h" |
#include "google_apis/gaia/gaia_auth_util.h" |
@@ -30,6 +33,10 @@ const FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Device Management"); |
const FilePath::CharType kTokenCacheFile[] = FILE_PATH_LITERAL("Token"); |
// File in the above directory for storing user policy data. |
const FilePath::CharType kPolicyCacheFile[] = FILE_PATH_LITERAL("Policy"); |
+// Path that contains the user policy key after the user's vault is mounted. |
+// "%s" must be substituted with the sanitized username. |
+const FilePath::CharType kPolicyKeyFile[] = |
+ FILE_PATH_LITERAL("/var/run/user_policy/%s.pub"); |
Mattias Nissler (ping if slow)
2013/02/04 16:44:57
can we make user_policy/%s a directory? That'd all
Joao da Silva
2013/02/06 00:34:37
In progress at https://gerrit.chromium.org/gerrit/
|
} // namespace |
@@ -146,11 +153,13 @@ CloudPolicyStore::Status LegacyPolicyCacheLoader::TranslateLoadResult( |
} |
UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS( |
+ chromeos::CryptohomeClient* cryptohome_client, |
chromeos::SessionManagerClient* session_manager_client, |
const std::string& username, |
const FilePath& legacy_token_cache_file, |
const FilePath& legacy_policy_cache_file) |
- : session_manager_client_(session_manager_client), |
+ : cryptohome_client_(cryptohome_client), |
+ session_manager_client_(session_manager_client), |
username_(username), |
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
legacy_cache_dir_(legacy_token_cache_file.DirName()), |
@@ -164,10 +173,12 @@ void UserCloudPolicyStoreChromeOS::Store( |
const em::PolicyFetchResponse& policy) { |
// Cancel all pending requests. |
weak_factory_.InvalidateWeakPtrs(); |
- Validate( |
- scoped_ptr<em::PolicyFetchResponse>(new em::PolicyFetchResponse(policy)), |
- base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated, |
- weak_factory_.GetWeakPtr())); |
+ scoped_ptr<em::PolicyFetchResponse> response( |
+ new em::PolicyFetchResponse(policy)); |
+ EnsurePolicyKeyLoaded( |
+ base::Bind(&UserCloudPolicyStoreChromeOS::ValidatePolicyForStore, |
+ weak_factory_.GetWeakPtr(), |
+ base::Passed(&response))); |
} |
void UserCloudPolicyStoreChromeOS::Load() { |
@@ -178,6 +189,64 @@ void UserCloudPolicyStoreChromeOS::Load() { |
weak_factory_.GetWeakPtr())); |
} |
+void UserCloudPolicyStoreChromeOS::ValidatePolicyForStore( |
+ scoped_ptr<em::PolicyFetchResponse> policy) { |
+ // Create and configure a validator. |
+ scoped_ptr<UserCloudPolicyValidator> validator = |
+ CreateValidator(policy.Pass()); |
+ validator->ValidateUsername(username_); |
+ if (policy_key_->key().empty()) { |
+ validator->ValidateInitialKey(); |
+ } else { |
+ const bool allow_rotation = true; |
+ validator->ValidateSignature(policy_key_->key(), allow_rotation); |
+ } |
+ |
+ // Start validation. The Validator will free itself once validation is |
+ // complete. |
+ validator.release()->StartValidation( |
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated, |
+ weak_factory_.GetWeakPtr())); |
+} |
+ |
+void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated( |
+ UserCloudPolicyValidator* validator) { |
+ validation_status_ = validator->status(); |
+ 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_->StoreUserPolicy( |
+ policy_blob, |
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored, |
+ weak_factory_.GetWeakPtr())); |
+} |
+ |
+void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) { |
+ if (!success) { |
+ status_ = STATUS_STORE_ERROR; |
+ NotifyStoreError(); |
+ } else { |
+ // Load the policy right after storing it, to make sure it was accepted by |
+ // the session manager. An additional validation is performed after the |
+ // load; reload the key for that validation too, in case it was rotated. |
+ // This method is the callback for a store operation, which is posted after |
+ // validating the policy, and the validation is performed after ensuring the |
+ // key is loaded, so |policy_key_| is valid here. |
+ policy_key_->Load(base::Bind(&UserCloudPolicyStoreChromeOS::Load, |
+ weak_factory_.GetWeakPtr())); |
+ } |
+} |
+ |
void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved( |
const std::string& policy_blob) { |
if (policy_blob.empty()) { |
@@ -206,9 +275,26 @@ void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved( |
return; |
} |
- Validate(policy.Pass(), |
- base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated, |
- weak_factory_.GetWeakPtr())); |
+ // Load |policy_key_| to verify the loaded policy. |
+ EnsurePolicyKeyLoaded( |
+ base::Bind(&UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy, |
+ weak_factory_.GetWeakPtr(), |
+ base::Passed(&policy))); |
+} |
+ |
+void UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy( |
+ scoped_ptr<em::PolicyFetchResponse> policy) { |
+ // Create and configure a validator for the loaded policy. |
+ scoped_ptr<UserCloudPolicyValidator> validator = |
+ CreateValidator(policy.Pass()); |
+ validator->ValidateUsername(username_); |
+ const bool allow_rotation = false; |
+ validator->ValidateSignature(policy_key_->key(), allow_rotation); |
+ // Start validation. The Validator will free itself once validation is |
+ // complete. |
+ validator.release()->StartValidation( |
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated, |
+ weak_factory_.GetWeakPtr())); |
} |
void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated( |
@@ -235,56 +321,6 @@ void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated( |
NotifyStoreLoaded(); |
} |
-void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated( |
- UserCloudPolicyValidator* validator) { |
- validation_status_ = validator->status(); |
- 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_->StoreUserPolicy( |
- policy_blob, |
- base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored, |
- weak_factory_.GetWeakPtr())); |
-} |
- |
-void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) { |
- if (!success) { |
- status_ = STATUS_STORE_ERROR; |
- NotifyStoreError(); |
- } else { |
- // TODO(mnissler): Once we do signature verifications, we'll have to reload |
- // the key at this point to account for key rotations. |
- Load(); |
- } |
-} |
- |
-void UserCloudPolicyStoreChromeOS::Validate( |
- scoped_ptr<em::PolicyFetchResponse> policy, |
- const UserCloudPolicyValidator::CompletionCallback& callback) { |
- // Configure the validator. |
- scoped_ptr<UserCloudPolicyValidator> validator = |
- CreateValidator(policy.Pass()); |
- validator->ValidateUsername(username_); |
- |
- // TODO(mnissler): Do a signature check here as well. The key is stored by |
- // session_manager in the root-owned cryptohome area, which is currently |
- // inaccessible to Chrome though. |
- |
- // Start validation. The Validator will free itself once validation is |
- // complete. |
- validator.release()->StartValidation(callback); |
-} |
- |
void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished( |
const std::string& dm_token, |
const std::string& device_id, |
@@ -292,10 +328,16 @@ void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished( |
scoped_ptr<em::PolicyFetchResponse> policy) { |
status_ = status; |
if (policy.get()) { |
- Validate(policy.Pass(), |
- base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated, |
- weak_factory_.GetWeakPtr(), |
- dm_token, device_id)); |
+ // Create and configure a validator for the loaded legacy policy. Note that |
+ // the signature on this policy is not verified. |
+ scoped_ptr<UserCloudPolicyValidator> validator = |
+ CreateValidator(policy.Pass()); |
+ validator->ValidateUsername(username_); |
+ validator.release()->StartValidation( |
+ base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated, |
+ weak_factory_.GetWeakPtr(), |
+ dm_token, |
+ device_id)); |
} else { |
InstallLegacyTokens(dm_token, device_id); |
} |
@@ -308,8 +350,7 @@ void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated( |
validation_status_ = validator->status(); |
if (validator->success()) { |
status_ = STATUS_OK; |
- InstallPolicy(validator->policy_data().Pass(), |
- validator->payload().Pass()); |
+ InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); |
// Clear the public key version. The public key version field would |
// otherwise indicate that we have key installed in the store when in fact |
@@ -346,4 +387,37 @@ void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(const FilePath& dir) { |
LOG(ERROR) << "Failed to remove cache dir " << dir.value(); |
} |
+void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded( |
+ const base::Closure& callback) { |
+ if (policy_key_) { |
+ callback.Run(); |
+ } else { |
+ // Get the hashed username that's part of the key's path, to create a new |
+ // |policy_key_| later. |
+ 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) { |
+ // EnsurePolicyKeyLoaded() may have been called twice before getting a reply |
+ // from dbus; the second request will just reload the key. |
+ if (!policy_key_) { |
+ // The default empty path will always yield an empty key. |
+ FilePath path; |
+ if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS && |
+ !sanitized_username.empty()) { |
+ path = FilePath( |
+ base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str())); |
+ } |
+ policy_key_.reset(new UserPolicyKey(path)); |
+ } |
+ policy_key_->Load(callback); |
+} |
+ |
} // namespace policy |