Chromium Code Reviews| 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 |