summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chromeos/login/login_utils_browsertest.cc25
-rw-r--r--chrome/browser/policy/browser_policy_connector.cc45
-rw-r--r--chrome/browser/policy/cros_user_policy_cache.cc414
-rw-r--r--chrome/browser/policy/cros_user_policy_cache.h126
-rw-r--r--chrome/browser/policy/cros_user_policy_cache_unittest.cc190
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/chrome_tests.gypi2
-rw-r--r--chrome/common/chrome_paths.cc3
-rw-r--r--chrome/common/chrome_paths.h2
9 files changed, 789 insertions, 22 deletions
diff --git a/chrome/browser/chromeos/login/login_utils_browsertest.cc b/chrome/browser/chromeos/login/login_utils_browsertest.cc
index 4137ce4..d5c8cdb 100644
--- a/chrome/browser/chromeos/login/login_utils_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_utils_browsertest.cc
@@ -49,6 +49,7 @@ namespace em = enterprise_management;
using ::testing::DoAll;
using ::testing::Return;
+using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::_;
using content::BrowserThread;
@@ -79,8 +80,12 @@ const char kDMPolicyRequest[] =
const char kDMToken[] = "1234";
-ACTION_P(MockSessionManagerClientPolicyCallback, policy) {
- arg0.Run(policy);
+ACTION_P(MockSessionManagerClientRetrievePolicyCallback, policy) {
+ arg0.Run(*policy);
+}
+
+ACTION_P(MockSessionManagerClientStorePolicyCallback, success) {
+ arg1.Run(success);
}
template<typename TESTBASE>
@@ -111,9 +116,6 @@ class LoginUtilsTestBase : public TESTBASE,
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
- // BrowserPolicyConnector makes the UserPolicyCache read relative to this
- // path. Make sure it's in a clean state.
- PathService::Override(chrome::DIR_USER_DATA, scoped_temp_dir_.path());
CommandLine* command_line = CommandLine::ForCurrentProcess();
command_line->AppendSwitch(switches::kEnableDevicePolicy);
@@ -132,7 +134,15 @@ class LoginUtilsTestBase : public TESTBASE,
MockSessionManagerClient* session_managed_client =
mock_dbus_thread_manager_.mock_session_manager_client();
EXPECT_CALL(*session_managed_client, RetrieveDevicePolicy(_))
- .WillRepeatedly(MockSessionManagerClientPolicyCallback(""));
+ .WillRepeatedly(
+ MockSessionManagerClientRetrievePolicyCallback(&device_policy_));
+ EXPECT_CALL(*session_managed_client, RetrieveUserPolicy(_))
+ .WillRepeatedly(
+ MockSessionManagerClientRetrievePolicyCallback(&user_policy_));
+ EXPECT_CALL(*session_managed_client, StoreUserPolicy(_, _))
+ .WillRepeatedly(
+ DoAll(SaveArg<0>(&user_policy_),
+ MockSessionManagerClientStorePolicyCallback(true)));
mock_async_method_caller_ = new cryptohome::MockAsyncMethodCaller;
cryptohome::AsyncMethodCaller::InitializeForTesting(
@@ -364,6 +374,9 @@ class LoginUtilsTestBase : public TESTBASE,
private:
ScopedTempDir scoped_temp_dir_;
+ std::string device_policy_;
+ std::string user_policy_;
+
DISALLOW_COPY_AND_ASSIGN(LoginUtilsTestBase);
};
diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc
index a29c610..1bb6bda 100644
--- a/chrome/browser/policy/browser_policy_connector.cc
+++ b/chrome/browser/policy/browser_policy_connector.cc
@@ -22,6 +22,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/pref_names.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "grit/generated_resources.h"
@@ -39,6 +40,7 @@
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/system/statistics_provider.h"
#include "chrome/browser/policy/app_pack_updater.h"
+#include "chrome/browser/policy/cros_user_policy_cache.h"
#include "chrome/browser/policy/device_policy_cache.h"
#include "chrome/browser/policy/network_configuration_updater.h"
#endif
@@ -311,23 +313,37 @@ void BrowserPolicyConnector::InitializeUserPolicy(
CommandLine* command_line = CommandLine::ForCurrentProcess();
- FilePath policy_dir;
- PathService::Get(chrome::DIR_USER_DATA, &policy_dir);
+ if (command_line->HasSwitch(switches::kDeviceManagementUrl)) {
+ user_data_store_.reset(CloudPolicyDataStore::CreateForUserPolicies());
+
+ FilePath profile_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &profile_dir);
#if defined(OS_CHROMEOS)
- policy_dir = policy_dir.Append(
- command_line->GetSwitchValuePath(switches::kLoginProfile));
+ profile_dir = profile_dir.Append(
+ command_line->GetSwitchValuePath(switches::kLoginProfile));
#endif
+ const FilePath policy_dir = profile_dir.Append(kPolicyDir);
+ const FilePath policy_cache_file = policy_dir.Append(kPolicyCacheFile);
+ const FilePath token_cache_file = policy_dir.Append(kTokenCacheFile);
+ CloudPolicyCacheBase* user_policy_cache = NULL;
- if (command_line->HasSwitch(switches::kDeviceManagementUrl)) {
- FilePath policy_cache_dir = policy_dir.Append(kPolicyDir);
-
- UserPolicyCache* user_policy_cache =
- new UserPolicyCache(policy_cache_dir.Append(kPolicyCacheFile),
- wait_for_policy_fetch);
- user_data_store_.reset(CloudPolicyDataStore::CreateForUserPolicies());
+#if defined(OS_CHROMEOS)
+ user_policy_cache =
+ new CrosUserPolicyCache(
+ chromeos::DBusThreadManager::Get()->GetSessionManagerClient(),
+ user_data_store_.get(),
+ wait_for_policy_fetch,
+ token_cache_file,
+ policy_cache_file);
+#else
+ user_policy_cache = new UserPolicyCache(policy_cache_file,
+ wait_for_policy_fetch);
user_policy_token_cache_.reset(
- new UserPolicyTokenCache(user_data_store_.get(),
- policy_cache_dir.Append(kTokenCacheFile)));
+ new UserPolicyTokenCache(user_data_store_.get(), token_cache_file));
+
+ // Initiate the DM-Token load.
+ user_policy_token_cache_->Load();
+#endif
managed_cloud_provider_->SetUserPolicyCache(user_policy_cache);
recommended_cloud_provider_->SetUserPolicyCache(user_policy_cache);
@@ -335,9 +351,6 @@ void BrowserPolicyConnector::InitializeUserPolicy(
user_data_store_.get(),
user_policy_cache));
- // Initiate the DM-Token load.
- user_policy_token_cache_->Load();
-
user_data_store_->set_user_name(user_name);
user_data_store_->set_user_affiliation(GetUserAffiliation(user_name));
diff --git a/chrome/browser/policy/cros_user_policy_cache.cc b/chrome/browser/policy/cros_user_policy_cache.cc
new file mode 100644
index 0000000..19c0ba2
--- /dev/null
+++ b/chrome/browser/policy/cros_user_policy_cache.cc
@@ -0,0 +1,414 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/policy/cros_user_policy_cache.h"
+
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "chrome/browser/policy/proto/cloud_policy.pb.h"
+#include "chrome/browser/policy/proto/device_management_backend.pb.h"
+#include "chrome/browser/policy/proto/device_management_local.pb.h"
+#include "chromeos/dbus/session_manager_client.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace em = enterprise_management;
+
+namespace policy {
+
+// Decodes a CloudPolicySettings object into a policy map. The implementation is
+// generated code in policy/cloud_policy_generated.cc.
+void DecodePolicy(const em::CloudPolicySettings& policy,
+ PolicyMap* policies);
+
+// Takes care of sending a new policy blob to session manager and reports back
+// the status through a callback.
+class CrosUserPolicyCache::StorePolicyOperation {
+ public:
+ typedef base::Callback<void(bool)> StatusCallback;
+
+ StorePolicyOperation(
+ const em::PolicyFetchResponse& policy,
+ chromeos::SessionManagerClient* session_manager_client,
+ const StatusCallback& callback);
+
+ // Executes the operation.
+ void Run();
+
+ // Cancels a pending callback.
+ void Cancel();
+
+ const em::PolicyFetchResponse& policy() { return policy_; }
+
+ private:
+ // StorePolicyOperation manages its own lifetime.
+ ~StorePolicyOperation() {}
+
+ // A callback function suitable for passing to session_manager_client.
+ void OnPolicyStored(bool result);
+
+ em::PolicyFetchResponse policy_;
+ chromeos::SessionManagerClient* session_manager_client_;
+ StatusCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(StorePolicyOperation);
+};
+
+CrosUserPolicyCache::StorePolicyOperation::StorePolicyOperation(
+ const em::PolicyFetchResponse& policy,
+ chromeos::SessionManagerClient* session_manager_client,
+ const StatusCallback& callback)
+ : policy_(policy),
+ session_manager_client_(session_manager_client),
+ callback_(callback) {}
+
+void CrosUserPolicyCache::StorePolicyOperation::Run() {
+ std::string serialized;
+ if (!policy_.SerializeToString(&serialized)) {
+ LOG(ERROR) << "Failed to serialize policy protobuf!";
+ callback_.Run(false);
+ delete this;
+ }
+ session_manager_client_->StoreUserPolicy(
+ serialized,
+ base::Bind(&CrosUserPolicyCache::StorePolicyOperation::OnPolicyStored,
+ base::Unretained(this)));
+}
+
+void CrosUserPolicyCache::StorePolicyOperation::Cancel() {
+ callback_.Reset();
+}
+
+void CrosUserPolicyCache::StorePolicyOperation::OnPolicyStored(bool result) {
+ if (!callback_.is_null())
+ callback_.Run(result);
+ delete this;
+}
+
+class CrosUserPolicyCache::RetrievePolicyOperation {
+ public:
+ typedef base::Callback<void(bool, const em::PolicyFetchResponse&)>
+ ResultCallback;
+
+ RetrievePolicyOperation(
+ chromeos::SessionManagerClient* session_manager_client,
+ const ResultCallback& callback);
+
+ // Executes the operation.
+ void Run();
+
+ // Cancels a pending callback.
+ void Cancel();
+
+ private:
+ // RetrievePolicyOperation manages its own lifetime.
+ ~RetrievePolicyOperation() {}
+
+ // Decodes the policy data and triggers a signature check.
+ void OnPolicyRetrieved(const std::string& policy_blob);
+
+ chromeos::SessionManagerClient* session_manager_client_;
+ ResultCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(RetrievePolicyOperation);
+};
+
+CrosUserPolicyCache::RetrievePolicyOperation::RetrievePolicyOperation(
+ chromeos::SessionManagerClient* session_manager_client,
+ const ResultCallback& callback)
+ : session_manager_client_(session_manager_client),
+ callback_(callback) {}
+
+void CrosUserPolicyCache::RetrievePolicyOperation::Run() {
+ session_manager_client_->RetrieveUserPolicy(
+ base::Bind(
+ &CrosUserPolicyCache::RetrievePolicyOperation::OnPolicyRetrieved,
+ base::Unretained(this)));
+}
+
+void CrosUserPolicyCache::RetrievePolicyOperation::Cancel() {
+ callback_.Reset();
+}
+
+void CrosUserPolicyCache::RetrievePolicyOperation::OnPolicyRetrieved(
+ const std::string& policy_blob) {
+ bool status = true;
+ em::PolicyFetchResponse policy;
+ if (!policy.ParseFromString(policy_blob) ||
+ !policy.has_policy_data() ||
+ !policy.has_policy_data_signature()) {
+ LOG(ERROR) << "Failed to decode policy";
+ status = false;
+ }
+
+ if (!callback_.is_null())
+ callback_.Run(status, policy);
+ delete this;
+}
+
+CrosUserPolicyCache::CrosUserPolicyCache(
+ chromeos::SessionManagerClient* session_manager_client,
+ CloudPolicyDataStore* data_store,
+ bool wait_for_policy_fetch,
+ const FilePath& legacy_token_cache_file,
+ const FilePath& legacy_policy_cache_file)
+ : session_manager_client_(session_manager_client),
+ data_store_(data_store),
+ pending_policy_fetch_(wait_for_policy_fetch),
+ pending_disk_cache_load_(true),
+ store_operation_(NULL),
+ retrieve_operation_(NULL),
+ legacy_cache_dir_(legacy_token_cache_file.DirName()),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ legacy_token_cache_delegate_factory_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ legacy_policy_cache_delegate_factory_(this)) {
+ DCHECK_EQ(legacy_token_cache_file.DirName().value(),
+ legacy_policy_cache_file.DirName().value());
+
+ legacy_token_loader_ =
+ new UserPolicyTokenLoader(
+ legacy_token_cache_delegate_factory_.GetWeakPtr(),
+ legacy_token_cache_file);
+ legacy_policy_cache_ =
+ new UserPolicyDiskCache(
+ legacy_policy_cache_delegate_factory_.GetWeakPtr(),
+ legacy_policy_cache_file);
+}
+
+CrosUserPolicyCache::~CrosUserPolicyCache() {
+ CancelStore();
+ CancelRetrieve();
+}
+
+void CrosUserPolicyCache::Load() {
+ retrieve_operation_ =
+ new RetrievePolicyOperation(
+ session_manager_client_,
+ base::Bind(&CrosUserPolicyCache::OnPolicyLoadDone,
+ base::Unretained(this)));
+ retrieve_operation_->Run();
+}
+
+bool CrosUserPolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) {
+ CancelStore();
+ set_last_policy_refresh_time(base::Time::NowFromSystemTime());
+ pending_policy_fetch_ = true;
+ store_operation_ =
+ new StorePolicyOperation(policy,
+ session_manager_client_,
+ base::Bind(&CrosUserPolicyCache::OnPolicyStored,
+ base::Unretained(this)));
+ store_operation_->Run();
+ return true;
+}
+
+void CrosUserPolicyCache::SetUnmanaged() {
+ base::Time now(base::Time::NowFromSystemTime());
+ SetUnmanagedInternal(now);
+
+ // Construct a policy blob with unmanaged state.
+ em::PolicyData policy_data;
+ policy_data.set_policy_type(data_store_->policy_type());
+ policy_data.set_timestamp((now - base::Time::UnixEpoch()).InMilliseconds());
+ policy_data.set_state(em::PolicyData::UNMANAGED);
+
+ em::PolicyFetchResponse policy;
+ if (!policy_data.SerializeToString(policy.mutable_policy_data())) {
+ LOG(ERROR) << "Failed to serialize policy_data";
+ return;
+ }
+
+ SetPolicy(policy);
+}
+
+void CrosUserPolicyCache::SetFetchingDone() {
+ // If there is a pending policy store or reload, wait for that to complete
+ // before reporting fetching done.
+ if (store_operation_ || retrieve_operation_)
+ return;
+
+ pending_policy_fetch_ = false;
+ CheckIfDone();
+}
+
+bool CrosUserPolicyCache::DecodePolicyData(const em::PolicyData& policy_data,
+ PolicyMap* policies) {
+ em::CloudPolicySettings policy;
+ if (!policy.ParseFromString(policy_data.policy_value())) {
+ LOG(WARNING) << "Failed to parse CloudPolicySettings protobuf.";
+ return false;
+ }
+ DecodePolicy(policy, policies);
+ return true;
+}
+
+void CrosUserPolicyCache::OnTokenLoaded(const std::string& token,
+ const std::string& device_id) {
+ if (token.empty())
+ LOG(WARNING) << "Failed to load legacy token cache";
+
+ data_store_->set_device_id(device_id);
+ data_store_->SetDeviceToken(token, true);
+}
+
+void CrosUserPolicyCache::OnDiskCacheLoaded(
+ UserPolicyDiskCache::LoadResult result,
+ const em::CachedCloudPolicyResponse& policy) {
+ if (result == UserPolicyDiskCache::LOAD_RESULT_SUCCESS) {
+ if (policy.unmanaged())
+ SetUnmanagedInternal(base::Time::FromTimeT(policy.timestamp()));
+ else if (policy.has_cloud_policy())
+ InstallLegacyPolicy(policy.cloud_policy());
+ } else {
+ LOG(WARNING) << "Failed to load legacy policy cache: " << result;
+ }
+
+ pending_disk_cache_load_ = false;
+ CheckIfDone();
+}
+
+void CrosUserPolicyCache::OnPolicyStored(bool result) {
+ DCHECK(store_operation_);
+ CancelStore();
+ if (result) {
+ // Policy is stored successfully, reload from session_manager and apply.
+ // This helps us making sure we only use policy that session_manager has
+ // checked and confirmed to be good.
+ CancelRetrieve();
+ retrieve_operation_ =
+ new RetrievePolicyOperation(
+ session_manager_client_,
+ base::Bind(&CrosUserPolicyCache::OnPolicyReloadDone,
+ base::Unretained(this)));
+ retrieve_operation_->Run();
+
+ // Now that the new policy blob is installed, remove the old cache dir.
+ if (!legacy_cache_dir_.empty()) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&RemoveLegacyCacheDir,
+ legacy_cache_dir_));
+ }
+ } else {
+ LOG(ERROR) << "Failed to store user policy.";
+ InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
+ CloudPolicySubsystem::POLICY_LOCAL_ERROR);
+ pending_policy_fetch_ = false;
+ CheckIfDone();
+ }
+}
+
+void CrosUserPolicyCache::OnPolicyLoadDone(
+ bool result,
+ const em::PolicyFetchResponse& policy) {
+ DCHECK(retrieve_operation_);
+ CancelRetrieve();
+ if (!result) {
+ LOG(WARNING) << "No user policy present, trying legacy caches.";
+ legacy_token_loader_->Load();
+ legacy_policy_cache_->Load();
+ return;
+ }
+
+ // We have new-style policy, no need to clean up.
+ legacy_cache_dir_.clear();
+
+ em::PolicyData policy_data;
+ if (!policy_data.ParseFromString(policy.policy_data())) {
+ LOG(WARNING) << "Failed to parse PolicyData protobuf.";
+ InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
+ CloudPolicySubsystem::POLICY_LOCAL_ERROR);
+ data_store_->SetDeviceToken(std::string(), true);
+ } else if (policy_data.request_token().empty() ||
+ policy_data.username().empty() ||
+ policy_data.device_id().empty()) {
+ LOG(WARNING) << "Policy protobuf is missing credentials";
+ InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
+ CloudPolicySubsystem::POLICY_LOCAL_ERROR);
+ data_store_->SetDeviceToken(std::string(), true);
+ } else {
+ data_store_->set_device_id(policy_data.device_id());
+ data_store_->SetDeviceToken(policy_data.request_token(), true);
+ if (SetPolicyInternal(policy, NULL, true))
+ set_last_policy_refresh_time(base::Time::NowFromSystemTime());
+ }
+
+ pending_disk_cache_load_ = false;
+ CheckIfDone();
+}
+
+void CrosUserPolicyCache::OnPolicyReloadDone(
+ bool result,
+ const em::PolicyFetchResponse& policy) {
+ DCHECK(retrieve_operation_);
+ CancelRetrieve();
+ if (result) {
+ if (SetPolicyInternal(policy, NULL, false))
+ set_last_policy_refresh_time(base::Time::NowFromSystemTime());
+ } else {
+ InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
+ CloudPolicySubsystem::POLICY_LOCAL_ERROR);
+ }
+ pending_policy_fetch_ = false;
+ CheckIfDone();
+}
+
+void CrosUserPolicyCache::CancelStore() {
+ if (store_operation_) {
+ store_operation_->Cancel();
+ store_operation_ = NULL;
+ }
+}
+
+void CrosUserPolicyCache::CancelRetrieve() {
+ if (retrieve_operation_) {
+ retrieve_operation_->Cancel();
+ retrieve_operation_ = NULL;
+ }
+}
+
+void CrosUserPolicyCache::CheckIfDone() {
+ if (!pending_policy_fetch_ && !pending_disk_cache_load_) {
+ if (!IsReady())
+ SetReady();
+ CloudPolicyCacheBase::SetFetchingDone();
+ }
+}
+
+void CrosUserPolicyCache::InstallLegacyPolicy(
+ const em::PolicyFetchResponse& policy) {
+ em::PolicyFetchResponse mutable_policy(policy);
+ mutable_policy.clear_policy_data_signature();
+ mutable_policy.clear_new_public_key();
+ mutable_policy.clear_new_public_key_signature();
+ em::PolicyData policy_data;
+ if (!policy_data.ParseFromString(mutable_policy.policy_data())) {
+ LOG(ERROR) << "Failed to parse policy data.";
+ return;
+ }
+
+ policy_data.clear_public_key_version();
+ if (!policy_data.SerializeToString(mutable_policy.mutable_policy_data())) {
+ LOG(ERROR) << "Failed to serialize policy data.";
+ return;
+ }
+
+ base::Time timestamp;
+ if (SetPolicyInternal(mutable_policy, &timestamp, true))
+ set_last_policy_refresh_time(timestamp);
+}
+
+// static
+void CrosUserPolicyCache::RemoveLegacyCacheDir(const FilePath& dir) {
+ if (!file_util::Delete(dir, true))
+ PLOG(ERROR) << "Failed to remove " << dir.value();
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/cros_user_policy_cache.h b/chrome/browser/policy/cros_user_policy_cache.h
new file mode 100644
index 0000000..c31c45e
--- /dev/null
+++ b/chrome/browser/policy/cros_user_policy_cache.h
@@ -0,0 +1,126 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_POLICY_CROS_USER_POLICY_CACHE_H_
+#define CHROME_BROWSER_POLICY_CROS_USER_POLICY_CACHE_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/policy/cloud_policy_cache_base.h"
+#include "chrome/browser/policy/user_policy_disk_cache.h"
+#include "chrome/browser/policy/user_policy_token_cache.h"
+
+namespace chromeos {
+class SessionManagerClient;
+}
+
+namespace policy {
+
+class CloudPolicyDataStore;
+
+// User policy cache that talks to the ChromeOS login library in order to store
+// and fetch policy data.
+class CrosUserPolicyCache : public CloudPolicyCacheBase,
+ public UserPolicyTokenCache::Delegate,
+ public UserPolicyDiskCache::Delegate {
+ public:
+ CrosUserPolicyCache(chromeos::SessionManagerClient* session_manager_client,
+ CloudPolicyDataStore* data_store,
+ bool wait_for_policy_fetch,
+ const FilePath& legacy_token_cache_file,
+ const FilePath& legacy_policy_cache_file);
+ virtual ~CrosUserPolicyCache();
+
+ // CloudPolicyCacheBase implementation.
+ virtual void Load() OVERRIDE;
+ virtual bool SetPolicy(
+ const enterprise_management::PolicyFetchResponse& policy) OVERRIDE;
+ virtual void SetUnmanaged() OVERRIDE;
+ virtual void SetFetchingDone() OVERRIDE;
+
+ protected:
+ virtual bool DecodePolicyData(
+ const enterprise_management::PolicyData& policy_data,
+ PolicyMap* policies) OVERRIDE;
+
+ private:
+ class StorePolicyOperation;
+ class RetrievePolicyOperation;
+
+ // UserPolicyTokenLoader::Delegate:
+ virtual void OnTokenLoaded(const std::string& token,
+ const std::string& device_id) OVERRIDE;
+
+ // UserPolicyDiskCache::Delegate:
+ virtual void OnDiskCacheLoaded(
+ UserPolicyDiskCache::LoadResult result,
+ const enterprise_management::CachedCloudPolicyResponse& policy) OVERRIDE;
+
+ // Used as a callback for the policy store operation.
+ void OnPolicyStored(bool result);
+
+ // Callback for the initial policy load. Installs the policy and passes the
+ // loaded token and device ID to the data store.
+ void OnPolicyLoadDone(
+ bool result,
+ const enterprise_management::PolicyFetchResponse& policy);
+
+ // Callback for the policy retrieval operation run to reload the policy after
+ // new policy has been successfully stored. Installs the new policy in the
+ // cache and publishes it if successful.
+ void OnPolicyReloadDone(
+ bool result,
+ const enterprise_management::PolicyFetchResponse& policy);
+
+ void CancelStore();
+ void CancelRetrieve();
+
+ // Checks whether the disk cache and (if requested) the policy fetch
+ // (including the DBus roundtrips) has completed and generates ready or
+ // fetching done notifications if this is the case.
+ void CheckIfDone();
+
+ // Installs legacy policy, mangling it to remove any public keys, public key
+ // versions and signatures. This is done so on the next policy fetch the
+ // server ships down a new policy to be sent down to session_manager.
+ void InstallLegacyPolicy(
+ const enterprise_management::PolicyFetchResponse& policy);
+
+ // Removes the legacy cache dir.
+ static void RemoveLegacyCacheDir(const FilePath& dir);
+
+ chromeos::SessionManagerClient* session_manager_client_;
+ CloudPolicyDataStore* data_store_;
+
+ // Whether a policy fetch is pending before readiness is asserted.
+ bool pending_policy_fetch_;
+ bool pending_disk_cache_load_;
+
+ // Storage and retrieval operations that are currently in flight.
+ StorePolicyOperation* store_operation_;
+ RetrievePolicyOperation* retrieve_operation_;
+
+ // TODO(mnissler): Remove all the legacy policy support members below after
+ // the number of pre-M20 clients drops back to zero.
+ FilePath legacy_cache_dir_;
+
+ base::WeakPtrFactory<UserPolicyTokenCache::Delegate>
+ legacy_token_cache_delegate_factory_;
+ scoped_refptr<UserPolicyTokenLoader> legacy_token_loader_;
+
+ base::WeakPtrFactory<UserPolicyDiskCache::Delegate>
+ legacy_policy_cache_delegate_factory_;
+ scoped_refptr<UserPolicyDiskCache> legacy_policy_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrosUserPolicyCache);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_CROS_USER_POLICY_CACHE_H_
diff --git a/chrome/browser/policy/cros_user_policy_cache_unittest.cc b/chrome/browser/policy/cros_user_policy_cache_unittest.cc
new file mode 100644
index 0000000..afff499
--- /dev/null
+++ b/chrome/browser/policy/cros_user_policy_cache_unittest.cc
@@ -0,0 +1,190 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/scoped_temp_dir.h"
+#include "base/time.h"
+#include "chrome/browser/policy/cloud_policy_data_store.h"
+#include "chrome/browser/policy/cros_user_policy_cache.h"
+#include "chrome/browser/policy/proto/cloud_policy.pb.h"
+#include "chrome/browser/policy/proto/device_management_backend.pb.h"
+#include "chrome/browser/policy/proto/device_management_local.pb.h"
+#include "chromeos/dbus/mock_session_manager_client.h"
+#include "content/test/test_browser_thread.h"
+#include "policy/policy_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::InvokeArgument;
+using testing::_;
+
+namespace em = enterprise_management;
+
+// These should probably be moved to a more central place.
+ACTION_TEMPLATE(InvokeCallbackArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(p1)) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(::std::tr1::get<k>(args), p1));
+}
+ACTION_TEMPLATE(InvokeCallbackArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_2_VALUE_PARAMS(p1, p2)) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(::std::tr1::get<k>(args), p1, p2));
+}
+
+namespace policy {
+namespace {
+
+const char kFakeToken[] = "token";
+const char kFakeSignature[] = "signature";
+const char kFakeMachineName[] = "machine-name";
+const char kFakeUsername[] = "username";
+const int kFakePublicKeyVersion = 17;
+const char kFakeDeviceId[] = "device-id";
+
+class CrosUserPolicyCacheTest : public testing::Test {
+ protected:
+ CrosUserPolicyCacheTest()
+ : loop_(MessageLoop::TYPE_UI),
+ data_store_(CloudPolicyDataStore::CreateForUserPolicies()),
+ ui_thread_(content::BrowserThread::UI, &loop_),
+ file_thread_(content::BrowserThread::FILE, &loop_) {}
+
+ virtual void SetUp() {
+ ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
+ }
+
+ void CreatePolicyResponse(em::PolicyFetchResponse* response) {
+ em::CloudPolicySettings policy_settings;
+ policy_settings.mutable_showhomebutton()->set_showhomebutton(true);
+
+ em::PolicyData policy_data;
+ policy_data.set_policy_type(dm_protocol::kChromeUserPolicyType);
+ policy_data.set_timestamp((base::Time::NowFromSystemTime() -
+ base::Time::UnixEpoch()).InMilliseconds());
+ policy_data.set_request_token(kFakeToken);
+ ASSERT_TRUE(
+ policy_settings.SerializeToString(policy_data.mutable_policy_value()));
+ policy_data.set_machine_name(kFakeMachineName);
+ policy_data.set_public_key_version(kFakePublicKeyVersion);
+ policy_data.set_username(kFakeUsername);
+ policy_data.set_device_id(kFakeDeviceId);
+ policy_data.set_state(em::PolicyData::ACTIVE);
+
+ ASSERT_TRUE(policy_data.SerializeToString(response->mutable_policy_data()));
+ response->set_policy_data_signature(kFakeSignature);
+ }
+
+ FilePath token_file() {
+ return tmp_dir_.path().Append(FILE_PATH_LITERAL("token"));
+ }
+
+ FilePath policy_file() {
+ return tmp_dir_.path().Append(FILE_PATH_LITERAL("policy"));
+ }
+
+ MessageLoop loop_;
+
+ chromeos::MockSessionManagerClient session_manager_client_;
+ scoped_ptr<CloudPolicyDataStore> data_store_;
+
+ private:
+ content::TestBrowserThread ui_thread_;
+ content::TestBrowserThread file_thread_;
+ ScopedTempDir tmp_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrosUserPolicyCacheTest);
+};
+
+TEST_F(CrosUserPolicyCacheTest, InitAndSetPolicy) {
+ CrosUserPolicyCache cache(&session_manager_client_,
+ data_store_.get(),
+ false,
+ token_file(),
+ policy_file());
+ EXPECT_FALSE(cache.IsReady());
+ EXPECT_FALSE(data_store_->token_cache_loaded());
+
+ // Initialize the cache.
+ EXPECT_CALL(session_manager_client_, RetrieveUserPolicy(_))
+ .WillOnce(InvokeCallbackArgument<0>(std::string()));
+
+ cache.Load();
+ loop_.RunAllPending();
+
+ EXPECT_TRUE(cache.IsReady());
+ EXPECT_TRUE(data_store_->token_cache_loaded());
+ EXPECT_EQ(0U, cache.policy()->size());
+
+ // Set policy.
+ em::PolicyFetchResponse response;
+ CreatePolicyResponse(&response);
+ std::string serialized_response;
+ ASSERT_TRUE(response.SerializeToString(&serialized_response));
+ testing::Sequence seq;
+ EXPECT_CALL(session_manager_client_, StoreUserPolicy(serialized_response, _))
+ .InSequence(seq)
+ .WillOnce(InvokeCallbackArgument<1>(true));
+ EXPECT_CALL(session_manager_client_, RetrieveUserPolicy(_))
+ .InSequence(seq)
+ .WillOnce(InvokeCallbackArgument<0>(serialized_response));
+
+ EXPECT_TRUE(cache.SetPolicy(response));
+ loop_.RunAllPending();
+
+ EXPECT_EQ(1U, cache.policy()->size());
+ const PolicyMap::Entry* entry = cache.policy()->Get(key::kShowHomeButton);
+ ASSERT_TRUE(entry);
+ EXPECT_TRUE(base::FundamentalValue(true).Equals(entry->value));
+};
+
+TEST_F(CrosUserPolicyCacheTest, Migration) {
+ std::string data;
+
+ em::DeviceCredentials credentials;
+ credentials.set_device_token(kFakeToken);
+ credentials.set_device_id(kFakeDeviceId);
+ ASSERT_TRUE(credentials.SerializeToString(&data));
+ ASSERT_NE(-1, file_util::WriteFile(token_file(), data.c_str(), data.size()));
+
+ em::CachedCloudPolicyResponse policy;
+ CreatePolicyResponse(policy.mutable_cloud_policy());
+ ASSERT_TRUE(policy.SerializeToString(&data));
+ ASSERT_NE(-1, file_util::WriteFile(policy_file(), data.c_str(), data.size()));
+
+ CrosUserPolicyCache cache(&session_manager_client_,
+ data_store_.get(),
+ false,
+ token_file(),
+ policy_file());
+ EXPECT_FALSE(cache.IsReady());
+ EXPECT_FALSE(data_store_->token_cache_loaded());
+
+ // Initialize the cache.
+ EXPECT_CALL(session_manager_client_, RetrieveUserPolicy(_))
+ .WillOnce(InvokeCallbackArgument<0>(std::string()));
+
+ cache.Load();
+ loop_.RunAllPending();
+
+ EXPECT_TRUE(cache.IsReady());
+ EXPECT_TRUE(data_store_->token_cache_loaded());
+ EXPECT_EQ(kFakeDeviceId, data_store_->device_id());
+ EXPECT_EQ(kFakeToken, data_store_->device_token());
+ EXPECT_EQ(1U, cache.policy()->size());
+ const PolicyMap::Entry* entry = cache.policy()->Get(key::kShowHomeButton);
+ ASSERT_TRUE(entry);
+ EXPECT_TRUE(base::FundamentalValue(true).Equals(entry->value));
+};
+
+} // namespace
+} // namespace policy
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index b9e3d3e..1b8f255 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1562,6 +1562,8 @@
'browser/policy/configuration_policy_reader.h',
'browser/policy/delayed_work_scheduler.cc',
'browser/policy/delayed_work_scheduler.h',
+ 'browser/policy/cros_user_policy_cache.cc',
+ 'browser/policy/cros_user_policy_cache.h',
'browser/policy/device_management_service.cc',
'browser/policy/device_management_service.h',
'browser/policy/device_policy_cache.cc',
@@ -4105,6 +4107,8 @@
['exclude', 'browser/policy/app_pack_updater.h'],
['exclude', 'browser/policy/auto_enrollment_client.cc'],
['exclude', 'browser/policy/auto_enrollment_client.h'],
+ ['exclude', 'browser/policy/cros_user_policy_cache.cc'],
+ ['exclude', 'browser/policy/cros_user_policy_cache.h'],
['exclude', 'browser/policy/device_policy_cache.cc'],
['exclude', 'browser/policy/device_policy_cache.h'],
['exclude', 'browser/policy/device_status_collector.cc'],
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 4f51726..18b7d7c 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1577,6 +1577,7 @@
'browser/policy/testing_policy_url_fetcher_factory.h',
'browser/policy/url_blacklist_manager_unittest.cc',
'browser/policy/user_policy_cache_unittest.cc',
+ 'browser/policy/cros_user_policy_cache_unittest.cc',
'browser/preferences_mock_mac.cc',
'browser/preferences_mock_mac.h',
'browser/prefs/command_line_pref_store_unittest.cc',
@@ -2246,6 +2247,7 @@
['exclude', '^browser/oom_priority_manager_unittest.cc'],
['exclude', '^browser/policy/auto_enrollment_client_unittest.cc' ],
['exclude', '^browser/policy/configuration_policy_handler_chromeos_unittest.cc' ],
+ ['exclude', '^browser/policy/cros_user_policy_cache_unittest.cc'],
['exclude', '^browser/policy/device_policy_cache_unittest.cc'],
['exclude', '^browser/policy/device_status_collector_unittest.cc'],
['exclude', '^browser/policy/enterprise_install_attributes_unittest.cc' ],
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index 6d4849e..675a357 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -300,6 +300,9 @@ bool PathProvider(int key, FilePath* result) {
cur = cur.Append(FILE_PATH_LITERAL("chromeos"));
cur = cur.Append(FILE_PATH_LITERAL("libcros.so"));
break;
+ case chrome::DIR_USER_POLICY:
+ cur = FilePath(FILE_PATH_LITERAL("/home/chronos/root/enterprise"));
+ break;
#endif
// The following are only valid in the development environment, and
// will fail if executed from an installed executable (because the
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h
index 09988fc..738a61f 100644
--- a/chrome/common/chrome_paths.h
+++ b/chrome/common/chrome_paths.h
@@ -52,6 +52,8 @@ enum {
// on Chrome Mac. On Chrome OS, this path is
// used for OEM customization.
// Getting this path does not create it.
+ DIR_USER_POLICY, // Root-owned per-user private enterprise
+ // directory.
#endif
DIR_EXTERNAL_EXTENSIONS, // Directory where installer places .crx files.