diff options
author | jkummerow@chromium.org <jkummerow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-17 13:25:23 +0000 |
---|---|---|
committer | jkummerow@chromium.org <jkummerow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-17 13:25:23 +0000 |
commit | f8636972b3e1d3a9bbf7f86b6708c0f5d66571ae (patch) | |
tree | 1cc358fe9fc57efd09b612b261d484ad359bf1fe /chrome/browser | |
parent | d20e0b986707dd49ae7a2cad347f4e50140ec86e (diff) | |
download | chromium_src-f8636972b3e1d3a9bbf7f86b6708c0f5d66571ae.zip chromium_src-f8636972b3e1d3a9bbf7f86b6708c0f5d66571ae.tar.gz chromium_src-f8636972b3e1d3a9bbf7f86b6708c0f5d66571ae.tar.bz2 |
New policy protobuf protocol.
(Third attempt to land http://codereview.chromium.org/6409040/ -- now without memory leaks)
- cloud_policy.proto autogenerated from policy_templates.json
- C++ method decoding the protobuf also autogenerated from policy_templates.json
- changed policy fetching mechanism to fetch new-style policy protobufs
BUG=68309, chromium-os:11253, chromium-os:11255
TEST=CloudPolicyCacheTest.*; also manual test against python testserver
Review URL: http://codereview.chromium.org/6532019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75259 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
29 files changed, 1669 insertions, 1106 deletions
diff --git a/chrome/browser/policy/asynchronous_policy_provider.cc b/chrome/browser/policy/asynchronous_policy_provider.cc index e697b05..9b050ad 100644 --- a/chrome/browser/policy/asynchronous_policy_provider.cc +++ b/chrome/browser/policy/asynchronous_policy_provider.cc @@ -25,7 +25,7 @@ bool AsynchronousPolicyProvider::Provide( ConfigurationPolicyStoreInterface* store) { DCHECK(CalledOnValidThread()); DCHECK(loader_->policy()); - DecodePolicyValueTree(loader_->policy(), store); + ApplyPolicyValueTree(loader_->policy(), store); return true; } diff --git a/chrome/browser/policy/cloud_policy_cache.cc b/chrome/browser/policy/cloud_policy_cache.cc new file mode 100644 index 0000000..b81fb81 --- /dev/null +++ b/chrome/browser/policy/cloud_policy_cache.cc @@ -0,0 +1,417 @@ +// Copyright (c) 2011 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/cloud_policy_cache.h" + +#include <limits> + +#include "base/file_util.h" +#include "base/logging.h" +#include "base/task.h" +#include "base/values.h" +#include "chrome/browser/browser_thread.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_constants.h" +#include "chrome/browser/policy/proto/device_management_local.pb.h" + +using google::protobuf::RepeatedField; +using google::protobuf::RepeatedPtrField; + +// This CloudPolicyCache currently supports two protocols for the interaction +// with DMServer: the old "DevicePolicy" format, which is being used in the +// CrOS Pilot Program and will be deprecated afterwards, and the new +// "CloudPolicy" format, which will be used exclusively after the public launch +// of ChromeOS. + +namespace policy { + +// Decodes a CloudPolicySettings object into two maps with mandatory and +// recommended settings, respectively. The implementation is generated code +// in policy/cloud_policy_generated.cc. +void DecodePolicy(const em::CloudPolicySettings& policy, + PolicyMap* mandatory, PolicyMap* recommended); + +// Saves policy information to a file. +class PersistPolicyTask : public Task { + public: + PersistPolicyTask(const FilePath& path, + const em::CloudPolicyResponse* cloud_policy_response, + const em::DevicePolicyResponse* device_policy_response, + const bool is_unmanaged) + : path_(path), + cloud_policy_response_(cloud_policy_response), + device_policy_response_(device_policy_response), + is_unmanaged_(is_unmanaged) {} + + private: + // Task override. + virtual void Run(); + + const FilePath path_; + scoped_ptr<const em::CloudPolicyResponse> cloud_policy_response_; + scoped_ptr<const em::DevicePolicyResponse> device_policy_response_; + const bool is_unmanaged_; +}; + +void PersistPolicyTask::Run() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + std::string data; + em::CachedCloudPolicyResponse cached_policy; + if (cloud_policy_response_.get()) { + cached_policy.mutable_cloud_policy()->CopyFrom(*cloud_policy_response_); + } else if (device_policy_response_.get()) { + cached_policy.mutable_device_policy()->CopyFrom(*device_policy_response_); + cached_policy.set_timestamp(base::Time::NowFromSystemTime().ToTimeT()); + } + if (is_unmanaged_) { + cached_policy.set_unmanaged(true); + cached_policy.set_timestamp(base::Time::NowFromSystemTime().ToTimeT()); + } + if (!cached_policy.SerializeToString(&data)) { + LOG(WARNING) << "Failed to serialize policy data"; + return; + } + + int size = data.size(); + if (file_util::WriteFile(path_, data.c_str(), size) != size) { + LOG(WARNING) << "Failed to write " << path_.value(); + return; + } +} + +CloudPolicyCache::CloudPolicyCache( + const FilePath& backing_file_path) + : backing_file_path_(backing_file_path), + device_policy_(new DictionaryValue), + fresh_policy_(false), + is_unmanaged_(false), + has_device_policy_(false) { +} + +CloudPolicyCache::~CloudPolicyCache() {} + +void CloudPolicyCache::LoadPolicyFromFile() { + // TODO(jkummerow): This method is doing file IO during browser startup. In + // the long run it would be better to delay this until the FILE thread exists. + if (!file_util::PathExists(backing_file_path_) || fresh_policy_) { + return; + } + + // Read the protobuf from the file. + std::string data; + if (!file_util::ReadFileToString(backing_file_path_, &data)) { + LOG(WARNING) << "Failed to read policy data from " + << backing_file_path_.value(); + return; + } + + em::CachedCloudPolicyResponse cached_response; + if (!cached_response.ParseFromArray(data.c_str(), data.size())) { + LOG(WARNING) << "Failed to parse policy data read from " + << backing_file_path_.value(); + return; + } + base::Time timestamp; + PolicyMap mandatory_policy; + PolicyMap recommended_policy; + is_unmanaged_ = cached_response.unmanaged(); + if (is_unmanaged_ || cached_response.has_device_policy()) + timestamp = base::Time::FromTimeT(cached_response.timestamp()); + if (cached_response.has_cloud_policy()) { + DCHECK(!is_unmanaged_); + bool ok = DecodePolicyResponse(cached_response.cloud_policy(), + &mandatory_policy, + &recommended_policy, + ×tamp); + if (!ok) { + LOG(WARNING) << "Decoding policy data failed."; + return; + } + } + if (timestamp > base::Time::NowFromSystemTime()) { + LOG(WARNING) << "Rejected policy data from " << backing_file_path_.value() + << ", file is from the future."; + return; + } + // Swap in the new policy information. + if (is_unmanaged_) { + base::AutoLock lock(lock_); + last_policy_refresh_time_ = timestamp; + return; + } else if (cached_response.has_cloud_policy()) { + if (!fresh_policy_) { + base::AutoLock lock(lock_); + // The use of |Swap()| here makes sure that the old value in + // |mandatory_policy_| is deleted when |mandatory_policy| goes out of + // scope. (The same applies to |SetPolicy()| below.) + mandatory_policy_.Swap(&mandatory_policy); + recommended_policy_.Swap(&recommended_policy); + last_policy_refresh_time_ = timestamp; + has_device_policy_ = false; + } + } else if (cached_response.has_device_policy()) { + scoped_ptr<DictionaryValue> value( + DecodeDevicePolicy(cached_response.device_policy())); + if (!fresh_policy_) { + base::AutoLock lock(lock_); + device_policy_.reset(value.release()); + last_policy_refresh_time_ = timestamp; + has_device_policy_ = true; + } + } +} + +bool CloudPolicyCache::SetPolicy(const em::CloudPolicyResponse& policy) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + is_unmanaged_ = false; + base::Time timestamp; + PolicyMap mandatory_policy; + PolicyMap recommended_policy; + bool ok = DecodePolicyResponse(policy, &mandatory_policy, &recommended_policy, + ×tamp); + if (!ok) { + // TODO(jkummerow): Signal error to PolicyProvider. + return false; + } + const bool new_policy_differs = + !mandatory_policy.Equals(mandatory_policy_) || + !recommended_policy.Equals(recommended_policy_); + { + base::AutoLock lock(lock_); + mandatory_policy_.Swap(&mandatory_policy); + recommended_policy_.Swap(&recommended_policy); + fresh_policy_ = true; + last_policy_refresh_time_ = timestamp; + has_device_policy_ = false; + } + + if (timestamp > base::Time::NowFromSystemTime() + + base::TimeDelta::FromMinutes(1)) { + LOG(WARNING) << "Server returned policy with timestamp from the future, " + "not persisting to disk."; + } else { + em::CloudPolicyResponse* policy_copy = new em::CloudPolicyResponse; + policy_copy->CopyFrom(policy); + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + new PersistPolicyTask(backing_file_path_, policy_copy, NULL, false)); + } + return new_policy_differs; +} + +bool CloudPolicyCache::SetDevicePolicy(const em::DevicePolicyResponse& policy) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + is_unmanaged_ = false; + DictionaryValue* value = DecodeDevicePolicy(policy); + const bool new_policy_differs = !(value->Equals(device_policy_.get())); + base::Time now(base::Time::NowFromSystemTime()); + { + base::AutoLock lock(lock_); + device_policy_.reset(value); + fresh_policy_ = true; + last_policy_refresh_time_ = now; + has_device_policy_ = true; + } + + em::DevicePolicyResponse* policy_copy = new em::DevicePolicyResponse; + policy_copy->CopyFrom(policy); + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + new PersistPolicyTask(backing_file_path_, NULL, policy_copy, false)); + return new_policy_differs; +} + +DictionaryValue* CloudPolicyCache::GetDevicePolicy() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + base::AutoLock lock(lock_); + return device_policy_->DeepCopy(); +} + +const PolicyMap* CloudPolicyCache::GetMandatoryPolicy() const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return &mandatory_policy_; +} + +const PolicyMap* CloudPolicyCache::GetRecommendedPolicy() const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return &recommended_policy_; +} + +void CloudPolicyCache::SetUnmanaged() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + is_unmanaged_ = true; + { + base::AutoLock lock(lock_); + mandatory_policy_.Clear(); + recommended_policy_.Clear(); + device_policy_.reset(new DictionaryValue); + last_policy_refresh_time_ = base::Time::NowFromSystemTime(); + } + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + new PersistPolicyTask(backing_file_path_, NULL, NULL, true)); +} + +// static +bool CloudPolicyCache::DecodePolicyResponse( + const em::CloudPolicyResponse& policy_response, + PolicyMap* mandatory, + PolicyMap* recommended, + base::Time* timestamp) { + std::string data = policy_response.signed_response(); + + if (!VerifySignature(policy_response.signature(), data, + policy_response.certificate_chain())) { + LOG(WARNING) << "Failed to verify signature."; + return false; + } + + em::SignedCloudPolicyResponse response; + if (!response.ParseFromArray(data.c_str(), data.size())) { + LOG(WARNING) << "Failed to parse SignedCloudPolicyResponse protobuf."; + return false; + } + + // TODO(jkummerow): Verify response.device_token(). Needs final specification + // which token we're actually sending / expecting to get back. + + // TODO(jkummerow): Store response.device_name(), if we decide to transfer + // it from the server to the client. + + DCHECK(timestamp); + *timestamp = base::Time::FromTimeT(response.timestamp()); + DecodePolicy(response.settings(), mandatory, recommended); + return true; +} + +// static +bool CloudPolicyCache::VerifySignature( + const std::string& signature, + const std::string& data, + const RepeatedPtrField<std::string>& certificate_chain) { + // TODO(jkummerow): Implement this. Non-trivial because we want to do it + // for all platforms -> it's enough work to deserve its own CL. + // Don't forget to also verify the hostname of the server against the cert. + return true; +} + +// static +Value* CloudPolicyCache::DecodeIntegerValue(google::protobuf::int64 value) { + if (value < std::numeric_limits<int>::min() || + value > std::numeric_limits<int>::max()) { + LOG(WARNING) << "Integer value " << value + << " out of numeric limits, ignoring."; + return NULL; + } + + return Value::CreateIntegerValue(static_cast<int>(value)); +} + +// static +Value* CloudPolicyCache::DecodeValue(const em::GenericValue& value) { + if (!value.has_value_type()) + return NULL; + + switch (value.value_type()) { + case em::GenericValue::VALUE_TYPE_BOOL: + if (value.has_bool_value()) + return Value::CreateBooleanValue(value.bool_value()); + return NULL; + case em::GenericValue::VALUE_TYPE_INT64: + if (value.has_int64_value()) + return DecodeIntegerValue(value.int64_value()); + return NULL; + case em::GenericValue::VALUE_TYPE_STRING: + if (value.has_string_value()) + return Value::CreateStringValue(value.string_value()); + return NULL; + case em::GenericValue::VALUE_TYPE_DOUBLE: + if (value.has_double_value()) + return Value::CreateDoubleValue(value.double_value()); + return NULL; + case em::GenericValue::VALUE_TYPE_BYTES: + if (value.has_bytes_value()) { + std::string bytes = value.bytes_value(); + return BinaryValue::CreateWithCopiedBuffer(bytes.c_str(), bytes.size()); + } + return NULL; + case em::GenericValue::VALUE_TYPE_BOOL_ARRAY: { + ListValue* list = new ListValue; + RepeatedField<bool>::const_iterator i; + for (i = value.bool_array().begin(); i != value.bool_array().end(); ++i) + list->Append(Value::CreateBooleanValue(*i)); + return list; + } + case em::GenericValue::VALUE_TYPE_INT64_ARRAY: { + ListValue* list = new ListValue; + RepeatedField<google::protobuf::int64>::const_iterator i; + for (i = value.int64_array().begin(); + i != value.int64_array().end(); ++i) { + Value* int_value = DecodeIntegerValue(*i); + if (int_value) + list->Append(int_value); + } + return list; + } + case em::GenericValue::VALUE_TYPE_STRING_ARRAY: { + ListValue* list = new ListValue; + RepeatedPtrField<std::string>::const_iterator i; + for (i = value.string_array().begin(); + i != value.string_array().end(); ++i) + list->Append(Value::CreateStringValue(*i)); + return list; + } + case em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY: { + ListValue* list = new ListValue; + RepeatedField<double>::const_iterator i; + for (i = value.double_array().begin(); + i != value.double_array().end(); ++i) + list->Append(Value::CreateDoubleValue(*i)); + return list; + } + default: + NOTREACHED() << "Unhandled value type"; + } + + return NULL; +} + +// static +DictionaryValue* CloudPolicyCache::DecodeDevicePolicy( + const em::DevicePolicyResponse& policy) { + DictionaryValue* result = new DictionaryValue; + RepeatedPtrField<em::DevicePolicySetting>::const_iterator setting; + for (setting = policy.setting().begin(); + setting != policy.setting().end(); + ++setting) { + // Wrong policy key? Skip. + if (setting->policy_key().compare(kChromeDevicePolicySettingKey) != 0) + continue; + + // No policy value? Skip. + if (!setting->has_policy_value()) + continue; + + // Iterate through all the name-value pairs wrapped in |setting|. + const em::GenericSetting& policy_value(setting->policy_value()); + RepeatedPtrField<em::GenericNamedValue>::const_iterator named_value; + for (named_value = policy_value.named_value().begin(); + named_value != policy_value.named_value().end(); + ++named_value) { + if (named_value->has_value()) { + Value* decoded_value = + CloudPolicyCache::DecodeValue(named_value->value()); + if (decoded_value) + result->Set(named_value->name(), decoded_value); + } + } + } + return result; +} + +} // namespace policy diff --git a/chrome/browser/policy/device_management_policy_cache.h b/chrome/browser/policy/cloud_policy_cache.h index 50441eb..518e3f0 100644 --- a/chrome/browser/policy/device_management_policy_cache.h +++ b/chrome/browser/policy/cloud_policy_cache.h @@ -1,9 +1,11 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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_DEVICE_MANAGEMENT_POLICY_CACHE_H_ -#define CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_POLICY_CACHE_H_ +#ifndef CHROME_BROWSER_POLICY_CLOUD_POLICY_CACHE_H_ +#define CHROME_BROWSER_POLICY_CLOUD_POLICY_CACHE_H_ + +#include <string> #include "base/file_path.h" #include "base/gtest_prod_util.h" @@ -11,11 +13,17 @@ #include "base/scoped_ptr.h" #include "base/synchronization/lock.h" #include "base/time.h" +#include "chrome/browser/policy/configuration_policy_provider.h" +#include "chrome/browser/policy/policy_map.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" +#include "policy/configuration_policy_type.h" class DictionaryValue; +class ListValue; class Value; +using google::protobuf::RepeatedPtrField; + namespace policy { namespace em = enterprise_management; @@ -25,10 +33,10 @@ namespace em = enterprise_management; // to the service directly, but receives updated policy information through // SetPolicy() calls, which is then persisted and decoded into the internal // Value representation chrome uses. -class DeviceManagementPolicyCache { +class CloudPolicyCache { public: - explicit DeviceManagementPolicyCache(const FilePath& backing_file_path); - ~DeviceManagementPolicyCache(); + explicit CloudPolicyCache(const FilePath& backing_file_path); + ~CloudPolicyCache(); // Loads policy information from the backing file. Non-existing or erroneous // cache files are ignored. @@ -36,25 +44,50 @@ class DeviceManagementPolicyCache { // Resets the policy information. Returns true if the new policy is different // from the previously stored policy. - bool SetPolicy(const em::DevicePolicyResponse& policy); + bool SetPolicy(const em::CloudPolicyResponse& policy); + bool SetDevicePolicy(const em::DevicePolicyResponse& policy); // Gets the policy information. Ownership of the return value is transferred // to the caller. - DictionaryValue* GetPolicy(); + DictionaryValue* GetDevicePolicy(); + const PolicyMap* GetMandatoryPolicy() const; + const PolicyMap* GetRecommendedPolicy() const; - void SetDeviceUnmanaged(); - bool is_device_unmanaged() const { - return is_device_unmanaged_; + void SetUnmanaged(); + bool is_unmanaged() const { + return is_unmanaged_; } - // Returns the time as which the policy was last fetched. + // Returns the time at which the policy was last fetched. base::Time last_policy_refresh_time() const { return last_policy_refresh_time_; } + // Returns true if this cache holds (old-style) device policy that should be + // given preference over (new-style) mandatory/recommended policy. + bool has_device_policy() const { + return has_device_policy_; + } + private: + friend class CloudPolicyCacheTest; friend class DeviceManagementPolicyCacheDecodeTest; - FRIEND_TEST_ALL_PREFIXES(DeviceManagementPolicyCacheDecodeTest, DecodePolicy); + + // Decodes a CloudPolicyResponse into two (ConfigurationPolicyType -> Value*) + // maps and a timestamp. Also performs verification, returns NULL if any + // check fails. + static bool DecodePolicyResponse( + const em::CloudPolicyResponse& policy_response, + PolicyMap* mandatory, + PolicyMap* recommended, + base::Time* timestamp); + + // Returns true if |certificate_chain| is trusted and a |signature| created + // from it matches |data|. + static bool VerifySignature( + const std::string& signature, + const std::string& data, + const RepeatedPtrField<std::string>& certificate_chain); // Decodes an int64 value. Checks whether the passed value fits the numeric // limits of the value representation. Returns a value (ownership is @@ -67,23 +100,30 @@ class DeviceManagementPolicyCache { // Decodes a policy message and returns it in Value representation. Ownership // of the returned dictionary is transferred to the caller. - static DictionaryValue* DecodePolicy( + static DictionaryValue* DecodeDevicePolicy( const em::DevicePolicyResponse& response); // The file in which we store a cached version of the policy information. const FilePath backing_file_path_; - // Protects |policy_|. + // Protects both |mandatory_policy_| and |recommended_policy_| as well as + // |device_policy_|. base::Lock lock_; // Policy key-value information. - scoped_ptr<DictionaryValue> policy_; + PolicyMap mandatory_policy_; + PolicyMap recommended_policy_; + scoped_ptr<DictionaryValue> device_policy_; // Tracks whether the store received a SetPolicy() call, which overrides any // information loaded from the file. bool fresh_policy_; - bool is_device_unmanaged_; + bool is_unmanaged_; + + // Tracks whether the cache currently stores |device_policy_| that should be + // given preference over |mandatory_policy_| and |recommended_policy_|. + bool has_device_policy_; // The time at which the policy was last refreshed. base::Time last_policy_refresh_time_; @@ -91,4 +131,4 @@ class DeviceManagementPolicyCache { } // namespace policy -#endif // CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_POLICY_CACHE_H_ +#endif // CHROME_BROWSER_POLICY_CLOUD_POLICY_CACHE_H_ diff --git a/chrome/browser/policy/cloud_policy_cache_unittest.cc b/chrome/browser/policy/cloud_policy_cache_unittest.cc new file mode 100644 index 0000000..d9fc768 --- /dev/null +++ b/chrome/browser/policy/cloud_policy_cache_unittest.cc @@ -0,0 +1,620 @@ +// Copyright (c) 2011 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/cloud_policy_cache.h" + +#include <limits> +#include <string> + +#include "base/file_util.h" +#include "base/message_loop.h" +#include "base/scoped_temp_dir.h" +#include "base/values.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/proto/cloud_policy.pb.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" +// TODO(jkummerow): remove this import when removing old DMPC test cases. +#include "chrome/browser/policy/proto/device_management_constants.h" +#include "chrome/browser/policy/proto/device_management_local.pb.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace policy { + +// Decodes a CloudPolicySettings object into two maps with mandatory and +// recommended settings, respectively. The implementation is generated code +// in policy/cloud_policy_generated.cc. +void DecodePolicy(const em::CloudPolicySettings& policy, + PolicyMap* mandatory, PolicyMap* recommended); + +// The implementations of these methods are in cloud_policy_generated.cc. +Value* DecodeIntegerValue(google::protobuf::int64 value); +ListValue* DecodeStringList(const em::StringList& string_list); + +// Tests the device management policy cache. +class CloudPolicyCacheTest : public testing::Test { + protected: + CloudPolicyCacheTest() + : loop_(MessageLoop::TYPE_UI), + ui_thread_(BrowserThread::UI, &loop_), + file_thread_(BrowserThread::FILE, &loop_) {} + + void SetUp() { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + } + + void TearDown() { + loop_.RunAllPending(); + } + + // Creates a (signed) CloudPolicyResponse setting the given |homepage| and + // featuring the given |timestamp| (as issued by the server). + // Mildly hacky special feature: pass an empty string as |homepage| to get + // a completely empty policy. + em::CloudPolicyResponse* CreateHomepagePolicy( + const std::string& homepage, + const base::Time& timestamp, + const em::PolicyOptions::PolicyMode policy_mode) { + em::SignedCloudPolicyResponse signed_response; + if (homepage != "") { + em::CloudPolicySettings* settings = signed_response.mutable_settings(); + em::HomepageLocationProto* homepagelocation_proto = + settings->mutable_homepagelocation(); + homepagelocation_proto->set_homepagelocation(homepage); + homepagelocation_proto->mutable_policy_options()->set_mode(policy_mode); + } + signed_response.set_timestamp(timestamp.ToTimeT()); + std::string serialized_signed_response; + EXPECT_TRUE(signed_response.SerializeToString(&serialized_signed_response)); + + em::CloudPolicyResponse* response = new em::CloudPolicyResponse; + response->set_signed_response(serialized_signed_response); + // TODO(jkummerow): Set proper certificate_chain and signature (when + // implementing support for signature verification). + response->set_signature("TODO"); + response->add_certificate_chain("TODO"); + return response; + } + + void WritePolicy(const em::CloudPolicyResponse& policy) { + std::string data; + em::CachedCloudPolicyResponse cached_policy; + cached_policy.mutable_cloud_policy()->CopyFrom(policy); + EXPECT_TRUE(cached_policy.SerializeToString(&data)); + int size = static_cast<int>(data.size()); + EXPECT_EQ(size, file_util::WriteFile(test_file(), data.c_str(), size)); + } + + FilePath test_file() { + return temp_dir_.path().AppendASCII("CloudPolicyCacheTest"); + } + + MessageLoop loop_; + + private: + ScopedTempDir temp_dir_; + BrowserThread ui_thread_; + BrowserThread file_thread_; +}; + +TEST_F(CloudPolicyCacheTest, DecodePolicy) { + em::CloudPolicySettings settings; + settings.mutable_homepagelocation()->set_homepagelocation("chromium.org"); + settings.mutable_javascriptenabled()->set_javascriptenabled(true); + settings.mutable_javascriptenabled()->mutable_policy_options()->set_mode( + em::PolicyOptions::MANDATORY); + settings.mutable_policyrefreshrate()->set_policyrefreshrate(5); + settings.mutable_policyrefreshrate()->mutable_policy_options()->set_mode( + em::PolicyOptions::RECOMMENDED); + PolicyMap mandatory_policy; + PolicyMap recommended_policy; + DecodePolicy(settings, &mandatory_policy, &recommended_policy); + PolicyMap mandatory; + mandatory.Set(kPolicyHomepageLocation, + Value::CreateStringValue("chromium.org")); + mandatory.Set(kPolicyJavascriptEnabled, Value::CreateBooleanValue(true)); + PolicyMap recommended; + recommended.Set(kPolicyPolicyRefreshRate, Value::CreateIntegerValue(5)); + EXPECT_TRUE(mandatory.Equals(mandatory_policy)); + EXPECT_TRUE(recommended.Equals(recommended_policy)); +} + +TEST_F(CloudPolicyCacheTest, DecodeIntegerValue) { + const int min = std::numeric_limits<int>::min(); + const int max = std::numeric_limits<int>::max(); + scoped_ptr<Value> value( + DecodeIntegerValue(static_cast<google::protobuf::int64>(42))); + ASSERT_TRUE(value.get()); + FundamentalValue expected_42(42); + EXPECT_TRUE(value->Equals(&expected_42)); + value.reset( + DecodeIntegerValue(static_cast<google::protobuf::int64>(min - 1LL))); + EXPECT_EQ(NULL, value.get()); + value.reset(DecodeIntegerValue(static_cast<google::protobuf::int64>(min))); + ASSERT_TRUE(value.get()); + FundamentalValue expected_min(min); + EXPECT_TRUE(value->Equals(&expected_min)); + value.reset( + DecodeIntegerValue(static_cast<google::protobuf::int64>(max + 1LL))); + EXPECT_EQ(NULL, value.get()); + value.reset(DecodeIntegerValue(static_cast<google::protobuf::int64>(max))); + ASSERT_TRUE(value.get()); + FundamentalValue expected_max(max); + EXPECT_TRUE(value->Equals(&expected_max)); +} + +TEST_F(CloudPolicyCacheTest, DecodeStringList) { + em::StringList string_list; + string_list.add_entries("ponies"); + string_list.add_entries("more ponies"); + scoped_ptr<ListValue> decoded(DecodeStringList(string_list)); + ListValue expected; + expected.Append(Value::CreateStringValue("ponies")); + expected.Append(Value::CreateStringValue("more ponies")); + EXPECT_TRUE(decoded->Equals(&expected)); +} + +TEST_F(CloudPolicyCacheTest, Empty) { + CloudPolicyCache cache(test_file()); + PolicyMap empty; + EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); + EXPECT_TRUE(empty.Equals(*cache.GetRecommendedPolicy())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(CloudPolicyCacheTest, LoadNoFile) { + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + PolicyMap empty; + EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(CloudPolicyCacheTest, RejectFuture) { + scoped_ptr<em::CloudPolicyResponse> policy_response( + CreateHomepagePolicy("", base::Time::NowFromSystemTime() + + base::TimeDelta::FromMinutes(5), + em::PolicyOptions::MANDATORY)); + WritePolicy(*policy_response); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + PolicyMap empty; + EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(CloudPolicyCacheTest, LoadWithFile) { + scoped_ptr<em::CloudPolicyResponse> policy_response( + CreateHomepagePolicy("", base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + WritePolicy(*policy_response); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + PolicyMap empty; + EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); + EXPECT_NE(base::Time(), cache.last_policy_refresh_time()); + EXPECT_GE(base::Time::Now(), cache.last_policy_refresh_time()); +} + +TEST_F(CloudPolicyCacheTest, LoadWithData) { + scoped_ptr<em::CloudPolicyResponse> policy( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + WritePolicy(*policy); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + PolicyMap expected; + expected.Set(kPolicyHomepageLocation, + Value::CreateStringValue("http://www.example.com")); + EXPECT_TRUE(expected.Equals(*cache.GetMandatoryPolicy())); +} + +TEST_F(CloudPolicyCacheTest, SetPolicy) { + CloudPolicyCache cache(test_file()); + scoped_ptr<em::CloudPolicyResponse> policy( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + EXPECT_TRUE(cache.SetPolicy(*policy)); + scoped_ptr<em::CloudPolicyResponse> policy2( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + EXPECT_FALSE(cache.SetPolicy(*policy2)); + PolicyMap expected; + expected.Set(kPolicyHomepageLocation, + Value::CreateStringValue("http://www.example.com")); + PolicyMap empty; + EXPECT_TRUE(expected.Equals(*cache.GetMandatoryPolicy())); + EXPECT_TRUE(empty.Equals(*cache.GetRecommendedPolicy())); + policy.reset(CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::RECOMMENDED)); + EXPECT_TRUE(cache.SetPolicy(*policy)); + EXPECT_TRUE(expected.Equals(*cache.GetRecommendedPolicy())); + EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); +} + +TEST_F(CloudPolicyCacheTest, ResetPolicy) { + CloudPolicyCache cache(test_file()); + + scoped_ptr<em::CloudPolicyResponse> policy( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + EXPECT_TRUE(cache.SetPolicy(*policy)); + PolicyMap expected; + expected.Set(kPolicyHomepageLocation, + Value::CreateStringValue("http://www.example.com")); + EXPECT_TRUE(expected.Equals(*cache.GetMandatoryPolicy())); + + scoped_ptr<em::CloudPolicyResponse> empty_policy( + CreateHomepagePolicy("", base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + EXPECT_TRUE(cache.SetPolicy(*empty_policy)); + PolicyMap empty; + EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); +} + +TEST_F(CloudPolicyCacheTest, PersistPolicy) { + { + CloudPolicyCache cache(test_file()); + scoped_ptr<em::CloudPolicyResponse> policy( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + cache.SetPolicy(*policy); + } + + loop_.RunAllPending(); + + EXPECT_TRUE(file_util::PathExists(test_file())); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + PolicyMap expected; + expected.Set(kPolicyHomepageLocation, + Value::CreateStringValue("http://www.example.com")); + EXPECT_TRUE(expected.Equals(*cache.GetMandatoryPolicy())); +} + +TEST_F(CloudPolicyCacheTest, FreshPolicyOverride) { + scoped_ptr<em::CloudPolicyResponse> policy( + CreateHomepagePolicy("http://www.example.com", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + WritePolicy(*policy); + + CloudPolicyCache cache(test_file()); + scoped_ptr<em::CloudPolicyResponse> updated_policy( + CreateHomepagePolicy("http://www.chromium.org", + base::Time::NowFromSystemTime(), + em::PolicyOptions::MANDATORY)); + EXPECT_TRUE(cache.SetPolicy(*updated_policy)); + + cache.LoadPolicyFromFile(); + PolicyMap expected; + expected.Set(kPolicyHomepageLocation, + Value::CreateStringValue("http://www.chromium.org")); + EXPECT_TRUE(expected.Equals(*cache.GetMandatoryPolicy())); +} + +} // namespace policy + +// ================================================================== +// Everything below this line can go when we phase out support for +// the old (trusted testing/pilot program) policy format. + +// This is a (slightly updated) copy of the old +// device_management_policy_cache_unittest.cc. The new CloudPolicyCache +// supports the old DMPC's interface for now (until it is phased out), so for +// this transitional period, we keep these old test cases but apply them to the +// new implementation (CPC). + +namespace policy { + +// Wraps base functionaly for the test cases. +class DeviceManagementPolicyCacheTestBase : public testing::Test { + protected: + // Add a string policy setting to a policy response message. + void AddStringPolicy(em::DevicePolicyResponse* policy, + const std::string& name, + const std::string& value) { + em::DevicePolicySetting* setting = policy->add_setting(); + setting->set_policy_key(kChromeDevicePolicySettingKey); + em::GenericSetting* policy_value = setting->mutable_policy_value(); + em::GenericNamedValue* named_value = policy_value->add_named_value(); + named_value->set_name(name); + em::GenericValue* value_container = named_value->mutable_value(); + value_container->set_value_type(em::GenericValue::VALUE_TYPE_STRING); + value_container->set_string_value(value); + } +}; + +// Tests the device management policy cache. +class DeviceManagementPolicyCacheTest + : public DeviceManagementPolicyCacheTestBase { + protected: + DeviceManagementPolicyCacheTest() + : loop_(MessageLoop::TYPE_UI), + ui_thread_(BrowserThread::UI, &loop_), + file_thread_(BrowserThread::FILE, &loop_) {} + + void SetUp() { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + } + + void TearDown() { + loop_.RunAllPending(); + } + + void WritePolicy(const em::DevicePolicyResponse& policy, + const base::Time& timestamp) { + std::string data; + em::CachedCloudPolicyResponse cached_policy; + cached_policy.mutable_device_policy()->CopyFrom(policy); + cached_policy.set_timestamp(timestamp.ToTimeT()); + EXPECT_TRUE(cached_policy.SerializeToString(&data)); + int size = static_cast<int>(data.size()); + EXPECT_EQ(size, file_util::WriteFile(test_file(), data.c_str(), size)); + } + + FilePath test_file() { + return temp_dir_.path().AppendASCII("DeviceManagementPolicyCacheTest"); + } + + protected: + MessageLoop loop_; + + private: + ScopedTempDir temp_dir_; + BrowserThread ui_thread_; + BrowserThread file_thread_; +}; + +TEST_F(DeviceManagementPolicyCacheTest, Empty) { + CloudPolicyCache cache(test_file()); + DictionaryValue empty; + scoped_ptr<Value> policy(cache.GetDevicePolicy()); + EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(DeviceManagementPolicyCacheTest, LoadNoFile) { + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + DictionaryValue empty; + scoped_ptr<Value> policy(cache.GetDevicePolicy()); + EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(DeviceManagementPolicyCacheTest, RejectFuture) { + em::DevicePolicyResponse policy_response; + WritePolicy(policy_response, base::Time::NowFromSystemTime() + + base::TimeDelta::FromMinutes(5)); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + DictionaryValue empty; + scoped_ptr<Value> policy(cache.GetDevicePolicy()); + EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); +} + +TEST_F(DeviceManagementPolicyCacheTest, LoadWithFile) { + em::DevicePolicyResponse policy_response; + WritePolicy(policy_response, base::Time::NowFromSystemTime()); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + DictionaryValue empty; + scoped_ptr<Value> policy(cache.GetDevicePolicy()); + EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_NE(base::Time(), cache.last_policy_refresh_time()); + EXPECT_GE(base::Time::Now(), cache.last_policy_refresh_time()); +} + +TEST_F(DeviceManagementPolicyCacheTest, LoadWithData) { + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + WritePolicy(policy, base::Time::NowFromSystemTime()); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.example.com")); + scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); + EXPECT_TRUE(expected.Equals(policy_value.get())); +} + +TEST_F(DeviceManagementPolicyCacheTest, SetDevicePolicy) { + CloudPolicyCache cache(test_file()); + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + EXPECT_TRUE(cache.SetDevicePolicy(policy)); + em::DevicePolicyResponse policy2; + AddStringPolicy(&policy2, "HomepageLocation", "http://www.example.com"); + EXPECT_FALSE(cache.SetDevicePolicy(policy2)); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.example.com")); + scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); + EXPECT_TRUE(expected.Equals(policy_value.get())); +} + +TEST_F(DeviceManagementPolicyCacheTest, ResetPolicy) { + CloudPolicyCache cache(test_file()); + + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + EXPECT_TRUE(cache.SetDevicePolicy(policy)); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.example.com")); + scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); + EXPECT_TRUE(expected.Equals(policy_value.get())); + + EXPECT_TRUE(cache.SetDevicePolicy(em::DevicePolicyResponse())); + policy_value.reset(cache.GetDevicePolicy()); + DictionaryValue empty; + EXPECT_TRUE(empty.Equals(policy_value.get())); +} + +TEST_F(DeviceManagementPolicyCacheTest, PersistPolicy) { + { + CloudPolicyCache cache(test_file()); + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + cache.SetDevicePolicy(policy); + } + + loop_.RunAllPending(); + + EXPECT_TRUE(file_util::PathExists(test_file())); + CloudPolicyCache cache(test_file()); + cache.LoadPolicyFromFile(); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.example.com")); + scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); + EXPECT_TRUE(expected.Equals(policy_value.get())); +} + +TEST_F(DeviceManagementPolicyCacheTest, FreshPolicyOverride) { + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + WritePolicy(policy, base::Time::NowFromSystemTime()); + + CloudPolicyCache cache(test_file()); + em::DevicePolicyResponse updated_policy; + AddStringPolicy(&updated_policy, "HomepageLocation", + "http://www.chromium.org"); + EXPECT_TRUE(cache.SetDevicePolicy(updated_policy)); + + cache.LoadPolicyFromFile(); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.chromium.org")); + scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); + EXPECT_TRUE(expected.Equals(policy_value.get())); +} + +// Tests proper decoding of policy values. +class DeviceManagementPolicyCacheDecodeTest + : public DeviceManagementPolicyCacheTestBase { + protected: + void DecodeAndCheck(Value* expected_value_ptr) { + scoped_ptr<Value> expected_value(expected_value_ptr); + scoped_ptr<Value> decoded_value( + CloudPolicyCache::DecodeValue(value_)); + if (expected_value_ptr) { + ASSERT_TRUE(decoded_value.get()); + EXPECT_TRUE(decoded_value->Equals(expected_value.get())); + } else { + ASSERT_FALSE(decoded_value.get()); + } + } + + DictionaryValue* DecodeDevicePolicy(const em::DevicePolicyResponse policy) { + return CloudPolicyCache::DecodeDevicePolicy(policy); + } + + em::GenericValue value_; +}; + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Bool) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_BOOL); + value_.set_bool_value(true); + DecodeAndCheck(Value::CreateBooleanValue(true)); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64); + value_.set_int64_value(42); + DecodeAndCheck(Value::CreateIntegerValue(42)); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64Overflow) { + const int min = std::numeric_limits<int>::min(); + const int max = std::numeric_limits<int>::max(); + value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64); + value_.set_int64_value(min - 1LL); + DecodeAndCheck(NULL); + value_.set_int64_value(max + 1LL); + DecodeAndCheck(NULL); + value_.set_int64_value(min); + DecodeAndCheck(Value::CreateIntegerValue(min)); + value_.set_int64_value(max); + DecodeAndCheck(Value::CreateIntegerValue(max)); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, String) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_STRING); + value_.set_string_value("ponies!"); + DecodeAndCheck(Value::CreateStringValue("ponies!")); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Double) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_DOUBLE); + value_.set_double_value(0.42L); + DecodeAndCheck(Value::CreateDoubleValue(0.42L)); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Bytes) { + std::string data("binary ponies."); + value_.set_value_type(em::GenericValue::VALUE_TYPE_BYTES); + value_.set_bytes_value(data); + DecodeAndCheck( + BinaryValue::CreateWithCopiedBuffer(data.c_str(), data.size())); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, BoolArray) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_BOOL_ARRAY); + value_.add_bool_array(false); + value_.add_bool_array(true); + ListValue* list = new ListValue; + list->Append(Value::CreateBooleanValue(false)); + list->Append(Value::CreateBooleanValue(true)); + DecodeAndCheck(list); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64Array) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64_ARRAY); + value_.add_int64_array(42); + value_.add_int64_array(17); + ListValue* list = new ListValue; + list->Append(Value::CreateIntegerValue(42)); + list->Append(Value::CreateIntegerValue(17)); + DecodeAndCheck(list); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, StringArray) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_STRING_ARRAY); + value_.add_string_array("ponies"); + value_.add_string_array("more ponies"); + ListValue* list = new ListValue; + list->Append(Value::CreateStringValue("ponies")); + list->Append(Value::CreateStringValue("more ponies")); + DecodeAndCheck(list); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, DoubleArray) { + value_.set_value_type(em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY); + value_.add_double_array(0.42L); + value_.add_double_array(0.17L); + ListValue* list = new ListValue; + list->Append(Value::CreateDoubleValue(0.42L)); + list->Append(Value::CreateDoubleValue(0.17L)); + DecodeAndCheck(list); +} + +TEST_F(DeviceManagementPolicyCacheDecodeTest, DecodePolicy) { + em::DevicePolicyResponse policy; + AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); + scoped_ptr<Value> decoded(DecodeDevicePolicy(policy)); + DictionaryValue expected; + expected.Set("HomepageLocation", + Value::CreateStringValue("http://www.example.com")); + EXPECT_TRUE(expected.Equals(decoded.get())); +} + +} // namespace policy diff --git a/chrome/browser/policy/configuration_policy_provider.cc b/chrome/browser/policy/configuration_policy_provider.cc index 82ca864..3f8e3fd 100644 --- a/chrome/browser/policy/configuration_policy_provider.cc +++ b/chrome/browser/policy/configuration_policy_provider.cc @@ -5,6 +5,7 @@ #include "chrome/browser/policy/configuration_policy_provider.h" #include "base/values.h" +#include "chrome/browser/policy/policy_map.h" namespace policy { @@ -21,7 +22,7 @@ bool ConfigurationPolicyProvider::IsInitializationComplete() const { return true; } -void ConfigurationPolicyProvider::DecodePolicyValueTree( +void ConfigurationPolicyProvider::ApplyPolicyValueTree( const DictionaryValue* policies, ConfigurationPolicyStoreInterface* store) { const PolicyDefinitionList* policy_list(policy_definition_list()); @@ -36,6 +37,18 @@ void ConfigurationPolicyProvider::DecodePolicyValueTree( // supports it. } +void ConfigurationPolicyProvider::ApplyPolicyMap( + const PolicyMap* policies, + ConfigurationPolicyStoreInterface* store) { + const PolicyDefinitionList* policy_list(policy_definition_list()); + for (const PolicyDefinitionList::Entry* i = policy_list->begin; + i != policy_list->end; ++i) { + const Value* value = policies->Get(i->policy_type); + if (value && value->IsType(i->value_type)) + store->Apply(i->policy_type, value->DeepCopy()); + } +} + // Class ConfigurationPolicyObserverRegistrar. ConfigurationPolicyObserverRegistrar::ConfigurationPolicyObserverRegistrar() diff --git a/chrome/browser/policy/configuration_policy_provider.h b/chrome/browser/policy/configuration_policy_provider.h index af2cddf..32fc885 100644 --- a/chrome/browser/policy/configuration_policy_provider.h +++ b/chrome/browser/policy/configuration_policy_provider.h @@ -6,15 +6,19 @@ #define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_H_ #pragma once +#include <map> #include <string> #include "base/basictypes.h" #include "base/scoped_ptr.h" #include "base/values.h" #include "chrome/browser/policy/configuration_policy_store_interface.h" +#include "policy/configuration_policy_type.h" namespace policy { +class PolicyMap; + // A mostly-abstract super class for platform-specific policy providers. // Platform-specific policy providers (Windows Group Policy, gconf, // etc.) should implement a subclass of this class. @@ -59,9 +63,14 @@ class ConfigurationPolicyProvider { protected: // Decodes the value tree and writes the configuration to the given |store|. - void DecodePolicyValueTree(const DictionaryValue* policies, + void ApplyPolicyValueTree(const DictionaryValue* policies, ConfigurationPolicyStoreInterface* store); + // Writes the configuration found in the already-decoded map |policies| to + // the given |store|. + void ApplyPolicyMap(const PolicyMap* policies, + ConfigurationPolicyStoreInterface* store); + const PolicyDefinitionList* policy_definition_list() const { return policy_definition_list_; } diff --git a/chrome/browser/policy/configuration_policy_store_interface.h b/chrome/browser/policy/configuration_policy_store_interface.h index d3261a3..1d3bf43 100644 --- a/chrome/browser/policy/configuration_policy_store_interface.h +++ b/chrome/browser/policy/configuration_policy_store_interface.h @@ -7,8 +7,6 @@ #pragma once #include "base/basictypes.h" -// configuration_policy_type.h is generated. See policy_template.json for -// policy definitions. #include "policy/configuration_policy_type.h" class Value; diff --git a/chrome/browser/policy/device_management_backend.h b/chrome/browser/policy/device_management_backend.h index 114c7b7..f2fec0d 100644 --- a/chrome/browser/policy/device_management_backend.h +++ b/chrome/browser/policy/device_management_backend.h @@ -75,8 +75,12 @@ class DeviceManagementBackend : base::NonThreadSafe { public: virtual ~DevicePolicyResponseDelegate() {} + // Deprecated in favor of HandleCloudPolicyResponse. To be removed once + // DMServer supports the new protocol. virtual void HandlePolicyResponse( const em::DevicePolicyResponse& response) = 0; + virtual void HandleCloudPolicyResponse( + const em::CloudPolicyResponse& response) = 0; virtual void OnError(ErrorCode code) = 0; protected: @@ -106,6 +110,12 @@ class DeviceManagementBackend : base::NonThreadSafe { const em::DevicePolicyRequest& request, DevicePolicyResponseDelegate* delegate) = 0; + virtual void ProcessCloudPolicyRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DevicePolicyResponseDelegate* delegate) = 0; + protected: DeviceManagementBackend() {} diff --git a/chrome/browser/policy/device_management_backend_impl.cc b/chrome/browser/policy/device_management_backend_impl.cc index ed75f3f..b01cbf8 100644 --- a/chrome/browser/policy/device_management_backend_impl.cc +++ b/chrome/browser/policy/device_management_backend_impl.cc @@ -27,6 +27,8 @@ const char DeviceManagementBackendImpl::kValueRequestRegister[] = "register"; const char DeviceManagementBackendImpl::kValueRequestUnregister[] = "unregister"; const char DeviceManagementBackendImpl::kValueRequestPolicy[] = "policy"; +const char DeviceManagementBackendImpl::kValueRequestCloudPolicy[] = + "cloud_policy"; const char DeviceManagementBackendImpl::kValueDeviceType[] = "Chrome OS"; const char DeviceManagementBackendImpl::kValueAppType[] = "Chrome"; @@ -170,7 +172,10 @@ void DeviceManagementJobBase::HandleResponse( } if (response_code != 200) { - OnError(DeviceManagementBackend::kErrorHttpStatus); + if (response_code == 400) + OnError(DeviceManagementBackend::kErrorRequestInvalid); + else + OnError(DeviceManagementBackend::kErrorHttpStatus); return; } @@ -230,7 +235,17 @@ class DeviceManagementRegisterJob : public DeviceManagementJobBase { const std::string& auth_token, const std::string& device_id, const em::DeviceRegisterRequest& request, - DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate); + DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate) + : DeviceManagementJobBase( + backend_impl, + DeviceManagementBackendImpl::kValueRequestRegister, + device_id), + delegate_(delegate) { + SetAuthToken(auth_token); + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_register_request()->CopyFrom(request); + SetPayload(request_wrapper); + } virtual ~DeviceManagementRegisterJob() {} private: @@ -247,32 +262,25 @@ class DeviceManagementRegisterJob : public DeviceManagementJobBase { DISALLOW_COPY_AND_ASSIGN(DeviceManagementRegisterJob); }; -DeviceManagementRegisterJob::DeviceManagementRegisterJob( - DeviceManagementBackendImpl* backend_impl, - const std::string& auth_token, - const std::string& device_id, - const em::DeviceRegisterRequest& request, - DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate) - : DeviceManagementJobBase( - backend_impl, - DeviceManagementBackendImpl::kValueRequestRegister, - device_id), - delegate_(delegate) { - SetAuthToken(auth_token); - em::DeviceManagementRequest request_wrapper; - request_wrapper.mutable_register_request()->CopyFrom(request); - SetPayload(request_wrapper); -} - // Handles device unregistration jobs. class DeviceManagementUnregisterJob : public DeviceManagementJobBase { public: DeviceManagementUnregisterJob( DeviceManagementBackendImpl* backend_impl, - const std::string& device_id, const std::string& device_management_token, + const std::string& device_id, const em::DeviceUnregisterRequest& request, - DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate); + DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate) + : DeviceManagementJobBase( + backend_impl, + DeviceManagementBackendImpl::kValueRequestUnregister, + device_id), + delegate_(delegate) { + SetDeviceManagementToken(device_management_token); + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_unregister_request()->CopyFrom(request); + SetPayload(request_wrapper); + } virtual ~DeviceManagementUnregisterJob() {} private: @@ -289,23 +297,6 @@ class DeviceManagementUnregisterJob : public DeviceManagementJobBase { DISALLOW_COPY_AND_ASSIGN(DeviceManagementUnregisterJob); }; -DeviceManagementUnregisterJob::DeviceManagementUnregisterJob( - DeviceManagementBackendImpl* backend_impl, - const std::string& device_management_token, - const std::string& device_id, - const em::DeviceUnregisterRequest& request, - DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate) - : DeviceManagementJobBase( - backend_impl, - DeviceManagementBackendImpl::kValueRequestUnregister, - device_id), - delegate_(delegate) { - SetDeviceManagementToken(device_management_token); - em::DeviceManagementRequest request_wrapper; - request_wrapper.mutable_unregister_request()->CopyFrom(request); - SetPayload(request_wrapper); -} - // Handles policy request jobs. class DeviceManagementPolicyJob : public DeviceManagementJobBase { public: @@ -314,7 +305,17 @@ class DeviceManagementPolicyJob : public DeviceManagementJobBase { const std::string& device_management_token, const std::string& device_id, const em::DevicePolicyRequest& request, - DeviceManagementBackend::DevicePolicyResponseDelegate* delegate); + DeviceManagementBackend::DevicePolicyResponseDelegate* delegate) + : DeviceManagementJobBase( + backend_impl, + DeviceManagementBackendImpl::kValueRequestPolicy, + device_id), + delegate_(delegate) { + SetDeviceManagementToken(device_management_token); + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_policy_request()->CopyFrom(request); + SetPayload(request_wrapper); + } virtual ~DeviceManagementPolicyJob() {} private: @@ -331,22 +332,40 @@ class DeviceManagementPolicyJob : public DeviceManagementJobBase { DISALLOW_COPY_AND_ASSIGN(DeviceManagementPolicyJob); }; -DeviceManagementPolicyJob::DeviceManagementPolicyJob( - DeviceManagementBackendImpl* backend_impl, - const std::string& device_management_token, - const std::string& device_id, - const em::DevicePolicyRequest& request, - DeviceManagementBackend::DevicePolicyResponseDelegate* delegate) - : DeviceManagementJobBase( +// Handles cloud policy request jobs. +class CloudPolicyJob : public DeviceManagementJobBase { + public: + CloudPolicyJob( + DeviceManagementBackendImpl* backend_impl, + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DeviceManagementBackend::DevicePolicyResponseDelegate* delegate) + : DeviceManagementJobBase( backend_impl, - DeviceManagementBackendImpl::kValueRequestPolicy, + DeviceManagementBackendImpl::kValueRequestCloudPolicy, device_id), - delegate_(delegate) { - SetDeviceManagementToken(device_management_token); - em::DeviceManagementRequest request_wrapper; - request_wrapper.mutable_policy_request()->CopyFrom(request); - SetPayload(request_wrapper); -} + delegate_(delegate) { + SetDeviceManagementToken(device_management_token); + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_cloud_policy_request()->CopyFrom(request); + SetPayload(request_wrapper); + } + virtual ~CloudPolicyJob() {} + + private: + // DeviceManagementJobBase overrides. + virtual void OnError(DeviceManagementBackend::ErrorCode error) { + delegate_->OnError(error); + } + virtual void OnResponse(const em::DeviceManagementResponse& response) { + delegate_->HandleCloudPolicyResponse(response.cloud_policy_response()); + } + + DeviceManagementBackend::DevicePolicyResponseDelegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(CloudPolicyJob); +}; DeviceManagementBackendImpl::DeviceManagementBackendImpl( DeviceManagementService* service) @@ -409,4 +428,13 @@ void DeviceManagementBackendImpl::ProcessPolicyRequest( request, delegate)); } +void DeviceManagementBackendImpl::ProcessCloudPolicyRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DevicePolicyResponseDelegate* delegate) { + AddJob(new CloudPolicyJob(this, device_management_token, device_id, + request, delegate)); +} + } // namespace policy diff --git a/chrome/browser/policy/device_management_backend_impl.h b/chrome/browser/policy/device_management_backend_impl.h index d818b4d..40c7e11 100644 --- a/chrome/browser/policy/device_management_backend_impl.h +++ b/chrome/browser/policy/device_management_backend_impl.h @@ -36,7 +36,10 @@ class DeviceManagementBackendImpl : public DeviceManagementBackend { // String constants for the device and app type we report to the server. static const char kValueRequestRegister[]; static const char kValueRequestUnregister[]; + // Deprecated in favor of kValueRequestCloudPolicy. + // See DevicePolicyResponseDelegate::HandlePolicyResponse. static const char kValueRequestPolicy[]; + static const char kValueRequestCloudPolicy[]; static const char kValueDeviceType[]; static const char kValueAppType[]; @@ -63,11 +66,18 @@ class DeviceManagementBackendImpl : public DeviceManagementBackend { const std::string& device_id, const em::DeviceUnregisterRequest& request, DeviceUnregisterResponseDelegate* response_delegate); + // Deprecated in favor of ProcessCloudPolicyRequest. + // See DevicePolicyResponseDelegate::HandlePolicyResponse. virtual void ProcessPolicyRequest( const std::string& device_management_token, const std::string& device_id, const em::DevicePolicyRequest& request, DevicePolicyResponseDelegate* response_delegate); + virtual void ProcessCloudPolicyRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DevicePolicyResponseDelegate* delegate); // Keeps track of the jobs currently in flight. JobSet pending_jobs_; diff --git a/chrome/browser/policy/device_management_backend_mock.h b/chrome/browser/policy/device_management_backend_mock.h index 0533efc..01ac14d 100644 --- a/chrome/browser/policy/device_management_backend_mock.h +++ b/chrome/browser/policy/device_management_backend_mock.h @@ -40,6 +40,7 @@ class DevicePolicyResponseDelegateMock virtual ~DevicePolicyResponseDelegateMock(); MOCK_METHOD1(HandlePolicyResponse, void(const em::DevicePolicyResponse&)); + MOCK_METHOD1(HandleCloudPolicyResponse, void(const em::CloudPolicyResponse&)); MOCK_METHOD1(OnError, void(DeviceManagementBackend::ErrorCode error)); }; diff --git a/chrome/browser/policy/device_management_policy_cache.cc b/chrome/browser/policy/device_management_policy_cache.cc deleted file mode 100644 index ef8e6e1..0000000 --- a/chrome/browser/policy/device_management_policy_cache.cc +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) 2010 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/device_management_policy_cache.h" - -#include <limits> -#include <string> - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/task.h" -#include "base/values.h" -#include "chrome/browser/browser_thread.h" -#include "chrome/browser/policy/proto/device_management_constants.h" -#include "chrome/browser/policy/proto/device_management_local.pb.h" - -using google::protobuf::RepeatedField; -using google::protobuf::RepeatedPtrField; - -namespace policy { - -// Saves policy information to a file. -class PersistPolicyTask : public Task { - public: - PersistPolicyTask(const FilePath& path, - const em::DevicePolicyResponse* policy, - const base::Time& timestamp, - const bool is_device_unmanaged) - : path_(path), - policy_(policy), - timestamp_(timestamp), - is_device_unmanaged_(is_device_unmanaged) {} - - private: - // Task override. - virtual void Run(); - - const FilePath path_; - scoped_ptr<const em::DevicePolicyResponse> policy_; - const base::Time timestamp_; - const bool is_device_unmanaged_; -}; - -void PersistPolicyTask::Run() { - std::string data; - em::CachedDevicePolicyResponse cached_policy; - if (policy_.get()) - cached_policy.mutable_policy()->CopyFrom(*policy_); - if (is_device_unmanaged_) - cached_policy.set_unmanaged(true); - cached_policy.set_timestamp(timestamp_.ToInternalValue()); - if (!cached_policy.SerializeToString(&data)) { - LOG(WARNING) << "Failed to serialize policy data"; - return; - } - - int size = data.size(); - if (file_util::WriteFile(path_, data.c_str(), size) != size) { - LOG(WARNING) << "Failed to write " << path_.value(); - return; - } -} - -DeviceManagementPolicyCache::DeviceManagementPolicyCache( - const FilePath& backing_file_path) - : backing_file_path_(backing_file_path), - policy_(new DictionaryValue), - fresh_policy_(false), - is_device_unmanaged_(false) { -} - -DeviceManagementPolicyCache::~DeviceManagementPolicyCache() {} - -void DeviceManagementPolicyCache::LoadPolicyFromFile() { - if (!file_util::PathExists(backing_file_path_) || fresh_policy_) - return; - - // Read the protobuf from the file. - std::string data; - if (!file_util::ReadFileToString(backing_file_path_, &data)) { - LOG(WARNING) << "Failed to read policy data from " - << backing_file_path_.value(); - return; - } - - em::CachedDevicePolicyResponse cached_policy; - if (!cached_policy.ParseFromArray(data.c_str(), data.size())) { - LOG(WARNING) << "Failed to parse policy data read from " - << backing_file_path_.value(); - return; - } - - // Reject files that claim to be from the future. - base::Time timestamp = base::Time::FromInternalValue( - cached_policy.timestamp()); - if (timestamp > base::Time::NowFromSystemTime()) { - LOG(WARNING) << "Rejected policy data from " << backing_file_path_.value() - << ", file is from the future."; - return; - } - is_device_unmanaged_ = cached_policy.unmanaged(); - - // Decode and swap in the new policy information. - scoped_ptr<DictionaryValue> value(DecodePolicy(cached_policy.policy())); - { - base::AutoLock lock(lock_); - if (!fresh_policy_) - policy_.reset(value.release()); - last_policy_refresh_time_ = timestamp; - } -} - -bool DeviceManagementPolicyCache::SetPolicy( - const em::DevicePolicyResponse& policy) { - is_device_unmanaged_ = false; - DictionaryValue* value = DeviceManagementPolicyCache::DecodePolicy(policy); - const bool new_policy_differs = !(value->Equals(policy_.get())); - base::Time now(base::Time::NowFromSystemTime()); - { - base::AutoLock lock(lock_); - policy_.reset(value); - fresh_policy_ = true; - last_policy_refresh_time_ = now; - } - - em::DevicePolicyResponse* policy_copy = new em::DevicePolicyResponse; - policy_copy->CopyFrom(policy); - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - new PersistPolicyTask(backing_file_path_, policy_copy, now, false)); - return new_policy_differs; -} - -DictionaryValue* DeviceManagementPolicyCache::GetPolicy() { - base::AutoLock lock(lock_); - return policy_->DeepCopy(); -} - -void DeviceManagementPolicyCache::SetDeviceUnmanaged() { - is_device_unmanaged_ = true; - base::Time now(base::Time::NowFromSystemTime()); - { - base::AutoLock lock(lock_); - policy_.reset(new DictionaryValue); - last_policy_refresh_time_ = now; - } - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - new PersistPolicyTask(backing_file_path_, NULL, now, true)); -} - -// static -Value* DeviceManagementPolicyCache::DecodeIntegerValue( - google::protobuf::int64 value) { - if (value < std::numeric_limits<int>::min() || - value > std::numeric_limits<int>::max()) { - LOG(WARNING) << "Integer value " << value - << " out of numeric limits, ignoring."; - return NULL; - } - - return Value::CreateIntegerValue(static_cast<int>(value)); -} - -// static -Value* DeviceManagementPolicyCache::DecodeValue(const em::GenericValue& value) { - if (!value.has_value_type()) - return NULL; - - switch (value.value_type()) { - case em::GenericValue::VALUE_TYPE_BOOL: - if (value.has_bool_value()) - return Value::CreateBooleanValue(value.bool_value()); - return NULL; - case em::GenericValue::VALUE_TYPE_INT64: - if (value.has_int64_value()) - return DecodeIntegerValue(value.int64_value()); - return NULL; - case em::GenericValue::VALUE_TYPE_STRING: - if (value.has_string_value()) - return Value::CreateStringValue(value.string_value()); - return NULL; - case em::GenericValue::VALUE_TYPE_DOUBLE: - if (value.has_double_value()) - return Value::CreateDoubleValue(value.double_value()); - return NULL; - case em::GenericValue::VALUE_TYPE_BYTES: - if (value.has_bytes_value()) { - std::string bytes = value.bytes_value(); - return BinaryValue::CreateWithCopiedBuffer(bytes.c_str(), bytes.size()); - } - return NULL; - case em::GenericValue::VALUE_TYPE_BOOL_ARRAY: { - ListValue* list = new ListValue; - RepeatedField<bool>::const_iterator i; - for (i = value.bool_array().begin(); i != value.bool_array().end(); ++i) - list->Append(Value::CreateBooleanValue(*i)); - return list; - } - case em::GenericValue::VALUE_TYPE_INT64_ARRAY: { - ListValue* list = new ListValue; - RepeatedField<google::protobuf::int64>::const_iterator i; - for (i = value.int64_array().begin(); - i != value.int64_array().end(); ++i) { - Value* int_value = DecodeIntegerValue(*i); - if (int_value) - list->Append(int_value); - } - return list; - } - case em::GenericValue::VALUE_TYPE_STRING_ARRAY: { - ListValue* list = new ListValue; - RepeatedPtrField<std::string>::const_iterator i; - for (i = value.string_array().begin(); - i != value.string_array().end(); ++i) - list->Append(Value::CreateStringValue(*i)); - return list; - } - case em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY: { - ListValue* list = new ListValue; - RepeatedField<double>::const_iterator i; - for (i = value.double_array().begin(); - i != value.double_array().end(); ++i) - list->Append(Value::CreateDoubleValue(*i)); - return list; - } - default: - NOTREACHED() << "Unhandled value type"; - } - - return NULL; -} - -// static -DictionaryValue* DeviceManagementPolicyCache::DecodePolicy( - const em::DevicePolicyResponse& policy) { - DictionaryValue* result = new DictionaryValue; - RepeatedPtrField<em::DevicePolicySetting>::const_iterator setting; - for (setting = policy.setting().begin(); - setting != policy.setting().end(); - ++setting) { - // Wrong policy key? Skip. - if (setting->policy_key().compare(kChromeDevicePolicySettingKey) != 0) - continue; - - // No policy value? Skip. - if (!setting->has_policy_value()) - continue; - - // Iterate through all the name-value pairs wrapped in |setting|. - const em::GenericSetting& policy_value(setting->policy_value()); - RepeatedPtrField<em::GenericNamedValue>::const_iterator named_value; - for (named_value = policy_value.named_value().begin(); - named_value != policy_value.named_value().end(); - ++named_value) { - if (named_value->has_value()) { - Value* decoded_value = - DeviceManagementPolicyCache::DecodeValue(named_value->value()); - if (decoded_value) - result->Set(named_value->name(), decoded_value); - } - } - } - return result; -} - -} // namespace policy diff --git a/chrome/browser/policy/device_management_policy_cache_unittest.cc b/chrome/browser/policy/device_management_policy_cache_unittest.cc deleted file mode 100644 index 1fe98c8..0000000 --- a/chrome/browser/policy/device_management_policy_cache_unittest.cc +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright (c) 2010 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/device_management_policy_cache.h" - -#include <limits> -#include <string> - -#include "base/file_util.h" -#include "base/message_loop.h" -#include "base/scoped_temp_dir.h" -#include "base/values.h" -#include "chrome/browser/browser_thread.h" -#include "chrome/browser/policy/proto/device_management_constants.h" -#include "chrome/browser/policy/proto/device_management_local.pb.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace policy { - -// Wraps base functionaly for the test cases. -class DeviceManagementPolicyCacheTestBase : public testing::Test { - protected: - // Add a string policy setting to a policy response message. - void AddStringPolicy(em::DevicePolicyResponse* policy, - const std::string& name, - const std::string& value) { - em::DevicePolicySetting* setting = policy->add_setting(); - setting->set_policy_key(kChromeDevicePolicySettingKey); - em::GenericSetting* policy_value = setting->mutable_policy_value(); - em::GenericNamedValue* named_value = policy_value->add_named_value(); - named_value->set_name(name); - em::GenericValue* value_container = named_value->mutable_value(); - value_container->set_value_type(em::GenericValue::VALUE_TYPE_STRING); - value_container->set_string_value(value); - } -}; - -// Tests the device management policy cache. -class DeviceManagementPolicyCacheTest - : public DeviceManagementPolicyCacheTestBase { - protected: - DeviceManagementPolicyCacheTest() - : loop_(MessageLoop::TYPE_UI), - ui_thread_(BrowserThread::UI, &loop_), - file_thread_(BrowserThread::FILE, &loop_) {} - - void SetUp() { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - } - - void TearDown() { - loop_.RunAllPending(); - } - - void WritePolicy(const em::DevicePolicyResponse& policy, - const base::Time& timestamp) { - std::string data; - em::CachedDevicePolicyResponse cached_policy; - cached_policy.mutable_policy()->CopyFrom(policy); - cached_policy.set_timestamp(timestamp.ToInternalValue()); - EXPECT_TRUE(cached_policy.SerializeToString(&data)); - int size = static_cast<int>(data.size()); - EXPECT_EQ(size, file_util::WriteFile(test_file(), data.c_str(), size)); - } - - FilePath test_file() { - return temp_dir_.path().AppendASCII("DeviceManagementPolicyCacheTest"); - } - - protected: - MessageLoop loop_; - - private: - ScopedTempDir temp_dir_; - BrowserThread ui_thread_; - BrowserThread file_thread_; -}; - -TEST_F(DeviceManagementPolicyCacheTest, Empty) { - DeviceManagementPolicyCache cache(test_file()); - DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetPolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); - EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); -} - -TEST_F(DeviceManagementPolicyCacheTest, LoadNoFile) { - DeviceManagementPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); - DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetPolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); - EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); -} - -TEST_F(DeviceManagementPolicyCacheTest, RejectFuture) { - em::DevicePolicyResponse policy_response; - WritePolicy(policy_response, base::Time::NowFromSystemTime() + - base::TimeDelta::FromMinutes(5)); - DeviceManagementPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); - DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetPolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); - EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); -} - -TEST_F(DeviceManagementPolicyCacheTest, LoadWithFile) { - em::DevicePolicyResponse policy_response; - WritePolicy(policy_response, base::Time::NowFromSystemTime()); - DeviceManagementPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); - DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetPolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); - EXPECT_NE(base::Time(), cache.last_policy_refresh_time()); - EXPECT_GE(base::Time::Now(), cache.last_policy_refresh_time()); -} - -TEST_F(DeviceManagementPolicyCacheTest, LoadWithData) { - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - WritePolicy(policy, base::Time::NowFromSystemTime()); - DeviceManagementPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetPolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); -} - -TEST_F(DeviceManagementPolicyCacheTest, SetPolicy) { - DeviceManagementPolicyCache cache(test_file()); - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - EXPECT_TRUE(cache.SetPolicy(policy)); - em::DevicePolicyResponse policy2; - AddStringPolicy(&policy2, "HomepageLocation", "http://www.example.com"); - EXPECT_FALSE(cache.SetPolicy(policy2)); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetPolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); -} - -TEST_F(DeviceManagementPolicyCacheTest, ResetPolicy) { - DeviceManagementPolicyCache cache(test_file()); - - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - EXPECT_TRUE(cache.SetPolicy(policy)); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetPolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); - - EXPECT_TRUE(cache.SetPolicy(em::DevicePolicyResponse())); - policy_value.reset(cache.GetPolicy()); - DictionaryValue empty; - EXPECT_TRUE(empty.Equals(policy_value.get())); -} - -TEST_F(DeviceManagementPolicyCacheTest, PersistPolicy) { - { - DeviceManagementPolicyCache cache(test_file()); - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - cache.SetPolicy(policy); - } - - loop_.RunAllPending(); - - EXPECT_TRUE(file_util::PathExists(test_file())); - DeviceManagementPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetPolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); -} - -TEST_F(DeviceManagementPolicyCacheTest, FreshPolicyOverride) { - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - WritePolicy(policy, base::Time::NowFromSystemTime()); - - DeviceManagementPolicyCache cache(test_file()); - em::DevicePolicyResponse updated_policy; - AddStringPolicy(&updated_policy, "HomepageLocation", - "http://www.chromium.org"); - EXPECT_TRUE(cache.SetPolicy(updated_policy)); - - cache.LoadPolicyFromFile(); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.chromium.org")); - scoped_ptr<Value> policy_value(cache.GetPolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); -} - -// Tests proper decoding of policy values. -class DeviceManagementPolicyCacheDecodeTest - : public DeviceManagementPolicyCacheTestBase { - protected: - void DecodeAndCheck(Value* expected_value_ptr) { - scoped_ptr<Value> expected_value(expected_value_ptr); - scoped_ptr<Value> decoded_value( - DeviceManagementPolicyCache::DecodeValue(value_)); - if (expected_value_ptr) { - ASSERT_TRUE(decoded_value.get()); - EXPECT_TRUE(decoded_value->Equals(expected_value.get())); - } else { - ASSERT_FALSE(decoded_value.get()); - } - } - - em::GenericValue value_; -}; - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Bool) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_BOOL); - value_.set_bool_value(true); - DecodeAndCheck(Value::CreateBooleanValue(true)); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64); - value_.set_int64_value(42); - DecodeAndCheck(Value::CreateIntegerValue(42)); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64Overflow) { - const int min = std::numeric_limits<int>::min(); - const int max = std::numeric_limits<int>::max(); - value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64); - value_.set_int64_value(min - 1LL); - DecodeAndCheck(NULL); - value_.set_int64_value(max + 1LL); - DecodeAndCheck(NULL); - value_.set_int64_value(min); - DecodeAndCheck(Value::CreateIntegerValue(min)); - value_.set_int64_value(max); - DecodeAndCheck(Value::CreateIntegerValue(max)); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, String) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_STRING); - value_.set_string_value("ponies!"); - DecodeAndCheck(Value::CreateStringValue("ponies!")); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Double) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_DOUBLE); - value_.set_double_value(0.42L); - DecodeAndCheck(Value::CreateDoubleValue(0.42L)); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Bytes) { - std::string data("binary ponies."); - value_.set_value_type(em::GenericValue::VALUE_TYPE_BYTES); - value_.set_bytes_value(data); - DecodeAndCheck( - BinaryValue::CreateWithCopiedBuffer(data.c_str(), data.size())); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, BoolArray) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_BOOL_ARRAY); - value_.add_bool_array(false); - value_.add_bool_array(true); - ListValue* list = new ListValue; - list->Append(Value::CreateBooleanValue(false)); - list->Append(Value::CreateBooleanValue(true)); - DecodeAndCheck(list); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, Int64Array) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_INT64_ARRAY); - value_.add_int64_array(42); - value_.add_int64_array(17); - ListValue* list = new ListValue; - list->Append(Value::CreateIntegerValue(42)); - list->Append(Value::CreateIntegerValue(17)); - DecodeAndCheck(list); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, StringArray) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_STRING_ARRAY); - value_.add_string_array("ponies"); - value_.add_string_array("more ponies"); - ListValue* list = new ListValue; - list->Append(Value::CreateStringValue("ponies")); - list->Append(Value::CreateStringValue("more ponies")); - DecodeAndCheck(list); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, DoubleArray) { - value_.set_value_type(em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY); - value_.add_double_array(0.42L); - value_.add_double_array(0.17L); - ListValue* list = new ListValue; - list->Append(Value::CreateDoubleValue(0.42L)); - list->Append(Value::CreateDoubleValue(0.17L)); - DecodeAndCheck(list); -} - -TEST_F(DeviceManagementPolicyCacheDecodeTest, DecodePolicy) { - em::DevicePolicyResponse policy; - AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - scoped_ptr<Value> decoded(DeviceManagementPolicyCache::DecodePolicy(policy)); - DictionaryValue expected; - expected.Set("HomepageLocation", - Value::CreateStringValue("http://www.example.com")); - EXPECT_TRUE(expected.Equals(decoded.get())); -} - -} // namespace policy diff --git a/chrome/browser/policy/device_management_policy_provider.cc b/chrome/browser/policy/device_management_policy_provider.cc index 315a6d2..eaaf4d4 100644 --- a/chrome/browser/policy/device_management_policy_provider.cc +++ b/chrome/browser/policy/device_management_policy_provider.cc @@ -4,14 +4,16 @@ #include "chrome/browser/policy/device_management_policy_provider.h" +#include <algorithm> + #include "base/command_line.h" #include "base/file_util.h" #include "base/path_service.h" #include "base/rand_util.h" #include "base/task.h" #include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/cloud_policy_cache.h" #include "chrome/browser/policy/device_management_backend.h" -#include "chrome/browser/policy/device_management_policy_cache.h" #include "chrome/browser/policy/profile_policy_context.h" #include "chrome/browser/policy/proto/device_management_constants.h" #include "chrome/browser/profiles/profile.h" @@ -86,8 +88,13 @@ DeviceManagementPolicyProvider::~DeviceManagementPolicyProvider() { bool DeviceManagementPolicyProvider::Provide( ConfigurationPolicyStoreInterface* policy_store) { - scoped_ptr<DictionaryValue> policies(cache_->GetPolicy()); - DecodePolicyValueTree(policies.get(), policy_store); + if (cache_->has_device_policy()) { + scoped_ptr<DictionaryValue> policies(cache_->GetDevicePolicy()); + ApplyPolicyValueTree(policies.get(), policy_store); + } else { + ApplyPolicyMap(cache_->GetMandatoryPolicy(), policy_store); + // TODO(jkummerow, mnissler): provide recommended policy. + } return true; } @@ -98,13 +105,23 @@ bool DeviceManagementPolicyProvider::IsInitializationComplete() const { void DeviceManagementPolicyProvider::HandlePolicyResponse( const em::DevicePolicyResponse& response) { DCHECK(TokenAvailable()); - if (cache_->SetPolicy(response)) { + if (cache_->SetDevicePolicy(response)) { initial_fetch_done_ = true; NotifyCloudPolicyUpdate(); } SetState(STATE_POLICY_VALID); } +void DeviceManagementPolicyProvider::HandleCloudPolicyResponse( + const em::CloudPolicyResponse& response) { + DCHECK(TokenAvailable()); + if (cache_->SetPolicy(response)) { + initial_fetch_done_ = true; + NotifyCloudPolicyUpdate(); + } + SetState(STATE_POLICY_VALID); +} + void DeviceManagementPolicyProvider::OnError( DeviceManagementBackend::ErrorCode code) { DCHECK(TokenAvailable()); @@ -117,6 +134,12 @@ void DeviceManagementPolicyProvider::OnError( DeviceManagementBackend::kErrorServiceManagementNotSupported) { VLOG(1) << "The device is no longer managed, resetting device token."; SetState(STATE_TOKEN_RESET); + } else if (!fallback_to_old_protocol_ && + code == DeviceManagementBackend::kErrorRequestInvalid) { + LOG(WARNING) << "Device management server doesn't understand new protocol," + << " falling back to old request."; + fallback_to_old_protocol_ = true; + SetState(STATE_TOKEN_VALID); // Triggers SendPolicyRequest() immediately. } else { LOG(WARNING) << "Could not provide policy from the device manager (error = " << code << "), will retry in " @@ -140,7 +163,7 @@ void DeviceManagementPolicyProvider::OnTokenError() { void DeviceManagementPolicyProvider::OnNotManaged() { DCHECK(!TokenAvailable()); VLOG(1) << "This device is not managed."; - cache_->SetDeviceUnmanaged(); + cache_->SetUnmanaged(); SetState(STATE_UNMANAGED); } @@ -186,6 +209,7 @@ void DeviceManagementPolicyProvider::Initialize( DCHECK(profile); backend_.reset(backend); profile_ = profile; + fallback_to_old_protocol_ = false; storage_dir_ = GetOrCreateDeviceManagementDir(profile_->GetPath()); state_ = STATE_INITIALIZING; initial_fetch_done_ = false; @@ -201,13 +225,13 @@ void DeviceManagementPolicyProvider::Initialize( unmanaged_device_refresh_rate_ms_ = unmanaged_device_refresh_rate_ms; const FilePath policy_path = storage_dir_.Append(kPolicyFilename); - cache_.reset(new DeviceManagementPolicyCache(policy_path)); + cache_.reset(new CloudPolicyCache(policy_path)); cache_->LoadPolicyFromFile(); SetDeviceTokenFetcher(new DeviceTokenFetcher(backend_.get(), profile, GetTokenPath())); - if (cache_->is_device_unmanaged()) { + if (cache_->is_unmanaged()) { // This is a non-first login on an unmanaged device. SetState(STATE_UNMANAGED); } else { @@ -226,15 +250,23 @@ void DeviceManagementPolicyProvider::RemoveObserver( } void DeviceManagementPolicyProvider::SendPolicyRequest() { - em::DevicePolicyRequest policy_request; - policy_request.set_policy_scope(kChromePolicyScope); - em::DevicePolicySettingRequest* setting = - policy_request.add_setting_request(); - setting->set_key(kChromeDevicePolicySettingKey); - setting->set_watermark(""); - backend_->ProcessPolicyRequest(token_fetcher_->GetDeviceToken(), - token_fetcher_->GetDeviceID(), - policy_request, this); + if (!fallback_to_old_protocol_) { + em::CloudPolicyRequest policy_request; + policy_request.set_policy_scope(kChromePolicyScope); + backend_->ProcessCloudPolicyRequest(token_fetcher_->GetDeviceToken(), + token_fetcher_->GetDeviceID(), + policy_request, this); + } else { + em::DevicePolicyRequest policy_request; + policy_request.set_policy_scope(kChromePolicyScope); + em::DevicePolicySettingRequest* setting = + policy_request.add_setting_request(); + setting->set_key(kChromeDevicePolicySettingKey); + setting->set_watermark(""); + backend_->ProcessPolicyRequest(token_fetcher_->GetDeviceToken(), + token_fetcher_->GetDeviceID(), + policy_request, this); + } } void DeviceManagementPolicyProvider::RefreshTaskExecute() { diff --git a/chrome/browser/policy/device_management_policy_provider.h b/chrome/browser/policy/device_management_policy_provider.h index 592df9b..dd09628 100644 --- a/chrome/browser/policy/device_management_policy_provider.h +++ b/chrome/browser/policy/device_management_policy_provider.h @@ -21,8 +21,8 @@ class TokenService; namespace policy { +class CloudPolicyCache; class DeviceManagementBackend; -class DeviceManagementPolicyCache; // Provides policy fetched from the device management server. With the exception // of the Provide method, which can be called on the FILE thread, all public @@ -44,7 +44,9 @@ class DeviceManagementPolicyProvider // DevicePolicyResponseDelegate implementation: virtual void HandlePolicyResponse( - const em::DevicePolicyResponse& response); + const em::DevicePolicyResponse& response); // deprecated. + virtual void HandleCloudPolicyResponse( + const em::CloudPolicyResponse& response); virtual void OnError(DeviceManagementBackend::ErrorCode code); // DeviceTokenFetcher::Observer implementation: @@ -146,7 +148,8 @@ class DeviceManagementPolicyProvider scoped_ptr<DeviceManagementBackend> backend_; Profile* profile_; // weak - scoped_ptr<DeviceManagementPolicyCache> cache_; + scoped_ptr<CloudPolicyCache> cache_; + bool fallback_to_old_protocol_; scoped_refptr<DeviceTokenFetcher> token_fetcher_; DeviceTokenFetcher::ObserverRegistrar registrar_; ObserverList<ConfigurationPolicyProvider::Observer, true> observer_list_; diff --git a/chrome/browser/policy/device_management_policy_provider_unittest.cc b/chrome/browser/policy/device_management_policy_provider_unittest.cc index d0a0eaa..8dc3bf4 100644 --- a/chrome/browser/policy/device_management_policy_provider_unittest.cc +++ b/chrome/browser/policy/device_management_policy_provider_unittest.cc @@ -7,9 +7,9 @@ #include "base/scoped_temp_dir.h" #include "chrome/browser/browser_thread.h" #include "chrome/browser/net/gaia/token_service.h" +#include "chrome/browser/policy/cloud_policy_cache.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/configuration_policy_provider.h" -#include "chrome/browser/policy/device_management_policy_cache.h" #include "chrome/browser/policy/device_management_policy_provider.h" #include "chrome/browser/policy/mock_configuration_policy_store.h" #include "chrome/browser/policy/mock_device_management_backend.h" @@ -113,9 +113,8 @@ class DeviceManagementPolicyProviderTest : public testing::Test { MockConfigurationPolicyStore store; EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy( - key::kDisableSpdy, true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); SimulateSuccessfulLoginAndRunPending(); EXPECT_FALSE(waiting_for_initial_policies()); EXPECT_CALL(store, Apply(kPolicyDisableSpdy, _)).Times(1); @@ -138,7 +137,7 @@ class DeviceManagementPolicyProviderTest : public testing::Test { scoped_ptr<DeviceManagementPolicyProvider> provider_; protected: - DeviceManagementPolicyCache* cache(DeviceManagementPolicyProvider* provider) { + CloudPolicyCache* cache(DeviceManagementPolicyProvider* provider) { return provider->cache_.get(); } @@ -193,9 +192,8 @@ TEST_F(DeviceManagementPolicyProviderTest, SecondProvide) { // Simulate a app relaunch by constructing a new provider. Policy should be // refreshed (since that might be the purpose of the app relaunch). CreateNewProvider(); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy( - key::kDisableSpdy, true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); loop_.RunAllPending(); Mock::VerifyAndClearExpectations(backend_); @@ -203,7 +201,7 @@ TEST_F(DeviceManagementPolicyProviderTest, SecondProvide) { // Cached policy should still be available. MockConfigurationPolicyStore store; CreateNewProvider(); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorRequestFailed)); SimulateSuccessfulLoginAndRunPending(); @@ -231,15 +229,14 @@ TEST_F(DeviceManagementPolicyProviderTest, ErrorCausesNewRequest) { DeviceManagementBackend::kErrorRequestFailed)); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorRequestFailed)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorRequestFailed)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); } SimulateSuccessfulLoginAndRunPending(); } @@ -250,16 +247,13 @@ TEST_F(DeviceManagementPolicyProviderTest, RefreshPolicies) { CreateNewProvider(0, 0, 0, 1000 * 1000, 1000, 0); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorRequestFailed)); } @@ -273,14 +267,13 @@ TEST_F(DeviceManagementPolicyProviderTest, DeviceNotFound) { InSequence s; EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorServiceDeviceNotFound)); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); } SimulateSuccessfulLoginAndRunPending(); } @@ -292,14 +285,13 @@ TEST_F(DeviceManagementPolicyProviderTest, InvalidTokenOnPolicyRequest) { InSequence s; EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorServiceManagementTokenInvalid)); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); } SimulateSuccessfulLoginAndRunPending(); } @@ -312,13 +304,11 @@ TEST_F(DeviceManagementPolicyProviderTest, DeviceNoLongerManaged) { CreateNewProvider(0, 0, 0, 0, 0, 1000 * 1000); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorServiceManagementNotSupported)); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( @@ -341,7 +331,7 @@ TEST_F(DeviceManagementPolicyProviderTest, UnmanagedDevice) { SimulateSuccessfulLoginAndRunPending(); // (1) The provider's DMPolicyCache should know that the device is not // managed. - EXPECT_TRUE(cache(provider_.get())->is_device_unmanaged()); + EXPECT_TRUE(cache(provider_.get())->is_unmanaged()); // (2) On restart, the provider should detect that this is not the first // login. CreateNewProvider(1000 * 1000, 0, 0, 0, 0, 0); @@ -350,14 +340,43 @@ TEST_F(DeviceManagementPolicyProviderTest, UnmanagedDevice) { InSequence s; EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, - true)); + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); } SimulateSuccessfulLoginAndRunPending(); // (3) Since the backend call this time returned a device id, the "unmanaged" // marker should have been deleted. - EXPECT_FALSE(cache(provider_.get())->is_device_unmanaged()); + EXPECT_FALSE(cache(provider_.get())->is_unmanaged()); +} + +TEST_F(DeviceManagementPolicyProviderTest, FallbackToOldProtocol) { + { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence. + InSequence s; + CreateNewProvider(0, 0, 0, 0, 0, 1000 * 1000); + EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedRegister()); + // If the CloudPolicyRequest fails with kErrorRequestInvalid... + EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorRequestInvalid)); + // ...the client should fall back to a classic PolicyRequest... + EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedBooleanPolicy( + key::kDisableSpdy, true)); + // ...and remember this fallback for any future request, ... + EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorHttpStatus)); + // ...both after successful fetches and after errors. + EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorServiceManagementNotSupported)); + // Finally, we set the client to 'unmanaged' to stop its request stream. + EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailRegister( + DeviceManagementBackend::kErrorServiceManagementNotSupported)); + } + SimulateSuccessfulLoginAndRunPending(); } } // namespace policy diff --git a/chrome/browser/policy/mock_configuration_policy_provider.cc b/chrome/browser/policy/mock_configuration_policy_provider.cc index a2566b0..46f997c 100644 --- a/chrome/browser/policy/mock_configuration_policy_provider.cc +++ b/chrome/browser/policy/mock_configuration_policy_provider.cc @@ -15,23 +15,16 @@ MockConfigurationPolicyProvider::MockConfigurationPolicyProvider() initialization_complete_(false) { } -MockConfigurationPolicyProvider::~MockConfigurationPolicyProvider() { - STLDeleteValues(&policy_map_); -} +MockConfigurationPolicyProvider::~MockConfigurationPolicyProvider() {} void MockConfigurationPolicyProvider::AddPolicy(ConfigurationPolicyType policy, Value* value) { - std::swap(policy_map_[policy], value); - delete value; + policy_map_.Set(policy, value); } void MockConfigurationPolicyProvider::RemovePolicy( ConfigurationPolicyType policy) { - const PolicyMap::iterator entry = policy_map_.find(policy); - if (entry != policy_map_.end()) { - delete entry->second; - policy_map_.erase(entry); - } + policy_map_.Erase(policy); } void MockConfigurationPolicyProvider::SetInitializationComplete( @@ -52,4 +45,4 @@ bool MockConfigurationPolicyProvider::IsInitializationComplete() const { return initialization_complete_; } -} +} // namespace policy diff --git a/chrome/browser/policy/mock_configuration_policy_provider.h b/chrome/browser/policy/mock_configuration_policy_provider.h index 5620f81..f71f8db 100644 --- a/chrome/browser/policy/mock_configuration_policy_provider.h +++ b/chrome/browser/policy/mock_configuration_policy_provider.h @@ -10,6 +10,7 @@ #include <utility> #include "chrome/browser/policy/configuration_policy_provider.h" +#include "chrome/browser/policy/policy_map.h" #include "testing/gmock/include/gmock/gmock.h" namespace policy { @@ -36,8 +37,6 @@ class MockConfigurationPolicyProvider : public ConfigurationPolicyProvider { virtual void RemoveObserver( ConfigurationPolicyProvider::Observer* observer) {} - typedef std::map<ConfigurationPolicyType, Value*> PolicyMap; - PolicyMap policy_map_; bool initialization_complete_; }; diff --git a/chrome/browser/policy/mock_configuration_policy_store.cc b/chrome/browser/policy/mock_configuration_policy_store.cc index bda4688..1cbf438 100644 --- a/chrome/browser/policy/mock_configuration_policy_store.cc +++ b/chrome/browser/policy/mock_configuration_policy_store.cc @@ -14,20 +14,16 @@ MockConfigurationPolicyStore::MockConfigurationPolicyStore() { Invoke(this, &MockConfigurationPolicyStore::ApplyToMap)); } -MockConfigurationPolicyStore::~MockConfigurationPolicyStore() { - STLDeleteValues(&policy_map_); -} +MockConfigurationPolicyStore::~MockConfigurationPolicyStore() {} const Value* MockConfigurationPolicyStore::Get( ConfigurationPolicyType type) const { - PolicyMap::const_iterator entry(policy_map_.find(type)); - return entry == policy_map_.end() ? NULL : entry->second; + return policy_map_.Get(type); } void MockConfigurationPolicyStore::ApplyToMap( ConfigurationPolicyType policy, Value* value) { - std::swap(policy_map_[policy], value); - delete value; + policy_map_.Set(policy, value); } } // namespace policy diff --git a/chrome/browser/policy/mock_configuration_policy_store.h b/chrome/browser/policy/mock_configuration_policy_store.h index 472357d..14e4597 100644 --- a/chrome/browser/policy/mock_configuration_policy_store.h +++ b/chrome/browser/policy/mock_configuration_policy_store.h @@ -12,6 +12,7 @@ #include "base/stl_util-inl.h" #include "base/values.h" #include "chrome/browser/policy/configuration_policy_store_interface.h" +#include "chrome/browser/policy/policy_map.h" #include "testing/gmock/include/gmock/gmock.h" namespace policy { @@ -20,8 +21,6 @@ namespace policy { // settings as they get set. class MockConfigurationPolicyStore : public ConfigurationPolicyStoreInterface { public: - typedef std::map<ConfigurationPolicyType, Value*> PolicyMap; - MockConfigurationPolicyStore(); virtual ~MockConfigurationPolicyStore(); diff --git a/chrome/browser/policy/mock_device_management_backend.h b/chrome/browser/policy/mock_device_management_backend.h index a684e4f..54c8c8f 100644 --- a/chrome/browser/policy/mock_device_management_backend.h +++ b/chrome/browser/policy/mock_device_management_backend.h @@ -9,6 +9,7 @@ #include <map> #include <string> +#include "base/time.h" #include "base/values.h" #include "chrome/browser/policy/device_management_backend.h" #include "chrome/browser/policy/proto/device_management_constants.h" @@ -46,6 +47,12 @@ class MockDeviceManagementBackend : public DeviceManagementBackend { const em::DevicePolicyRequest& request, DevicePolicyResponseDelegate* delegate)); + MOCK_METHOD4(ProcessCloudPolicyRequest, void( + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DevicePolicyResponseDelegate* delegate)); + private: DISALLOW_COPY_AND_ASSIGN(MockDeviceManagementBackend); }; @@ -73,6 +80,24 @@ ACTION_P2(MockDeviceManagementBackendSucceedBooleanPolicy, name, value) { arg3->HandlePolicyResponse(response); } +ACTION(MockDeviceManagementBackendSucceedSpdyCloudPolicy) { + em::SignedCloudPolicyResponse signed_response; + em::CloudPolicySettings* settings = signed_response.mutable_settings(); + em::DisableSpdyProto* spdy_proto = settings->mutable_disablespdy(); + spdy_proto->set_disablespdy(true); + spdy_proto->mutable_policy_options()->set_mode(em::PolicyOptions::MANDATORY); + signed_response.set_timestamp(base::Time::NowFromSystemTime().ToTimeT()); + std::string serialized_signed_response; + EXPECT_TRUE(signed_response.SerializeToString(&serialized_signed_response)); + em::CloudPolicyResponse response; + response.set_signed_response(serialized_signed_response); + // TODO(jkummerow): Set proper certificate_chain and signature (when + // implementing support for signature verification). + response.set_signature("TODO"); + response.add_certificate_chain("TODO"); + arg3->HandleCloudPolicyResponse(response); +} + ACTION_P(MockDeviceManagementBackendFailRegister, error) { arg3->OnError(error); } diff --git a/chrome/browser/policy/policy_map.cc b/chrome/browser/policy/policy_map.cc new file mode 100644 index 0000000..50c8c42 --- /dev/null +++ b/chrome/browser/policy/policy_map.cc @@ -0,0 +1,73 @@ +// Copyright (c) 2011 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/policy_map.h" + +#include <algorithm> + +#include "base/stl_util-inl.h" + +namespace policy { + +PolicyMap::PolicyMap() { +} + +PolicyMap::~PolicyMap() { + Clear(); +} + +const Value* PolicyMap::Get(ConfigurationPolicyType policy) const { + PolicyMapType::const_iterator entry = map_.find(policy); + return entry == map_.end() ? NULL : entry->second; +} + +void PolicyMap::Set(ConfigurationPolicyType policy, Value* value) { + std::swap(map_[policy], value); + delete value; +} + +void PolicyMap::Erase(ConfigurationPolicyType policy) { + const const_iterator entry = map_.find(policy); + if (entry != map_.end()) { + delete entry->second; + map_.erase(entry->first); + } +} + +void PolicyMap::Swap(PolicyMap* other) { + map_.swap(other->map_); +} + +bool PolicyMap::Equals(const PolicyMap& other) const { + return other.map_.size() == map_.size() && + std::equal(map_.begin(), map_.end(), other.map_.begin(), MapEntryEquals); +} + +bool PolicyMap::empty() const { + return map_.empty(); +} + +size_t PolicyMap::size() const { + return map_.size(); +} + +PolicyMap::const_iterator PolicyMap::begin() const { + return map_.begin(); +} + +PolicyMap::const_iterator PolicyMap::end() const { + return map_.end(); +} + +void PolicyMap::Clear() { + STLDeleteValues(&map_); +} + +// static +bool PolicyMap::MapEntryEquals(const PolicyMap::PolicyMapType::value_type& a, + const PolicyMap::PolicyMapType::value_type& b) { + return a.first == b.first && Value::Equals(a.second, b.second); +} + +} // namespace policy diff --git a/chrome/browser/policy/policy_map.h b/chrome/browser/policy/policy_map.h new file mode 100644 index 0000000..c9e3d03 --- /dev/null +++ b/chrome/browser/policy/policy_map.h @@ -0,0 +1,58 @@ +// Copyright (c) 2011 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_POLICY_MAP_H_ +#define CHROME_BROWSER_POLICY_POLICY_MAP_H_ + +#include <map> + +#include "base/values.h" +#include "policy/configuration_policy_type.h" + +namespace policy { + +// Wrapper class around a std::map<ConfigurationPolicyType, Value*> that +// properly cleans up after itself when going out of scope. +// Exposes interesting methods of the underlying std::map. +class PolicyMap { + public: + typedef std::map<ConfigurationPolicyType, Value*> PolicyMapType; + typedef PolicyMapType::const_iterator const_iterator; + + PolicyMap(); + virtual ~PolicyMap(); + + // Returns a weak reference to the value currently stored for key |policy|. + // Ownership is retained by PolicyMap; callers should use Value::DeepCopy + // if they need a copy that they own themselves. + // Returns NULL if the map does not contain a value for |policy|. + const Value* Get(ConfigurationPolicyType policy) const; + // Takes ownership of |value|. Overwrites any existing value stored in the + // map for the key |policy|. + void Set(ConfigurationPolicyType policy, Value* value); + void Erase(ConfigurationPolicyType policy); + + void Swap(PolicyMap* other); + + bool Equals(const PolicyMap& other) const; + bool empty() const; + size_t size() const; + + const_iterator begin() const; + const_iterator end() const; + void Clear(); + + private: + // Helper function for Equals(...). + static bool MapEntryEquals(const PolicyMapType::value_type& a, + const PolicyMapType::value_type& b); + + PolicyMapType map_; + + DISALLOW_COPY_AND_ASSIGN(PolicyMap); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_POLICY_MAP_H_ diff --git a/chrome/browser/policy/policy_map_unittest.cc b/chrome/browser/policy/policy_map_unittest.cc new file mode 100644 index 0000000..01aad95 --- /dev/null +++ b/chrome/browser/policy/policy_map_unittest.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2011 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/policy_map.h" + +#include "base/scoped_ptr.h" +#include "policy/configuration_policy_type.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace policy { + +TEST(PolicyMapTest, SetAndGet) { + PolicyMap map; + map.Set(kPolicyHomepageLocation, Value::CreateStringValue("aaa")); + StringValue expected("aaa"); + EXPECT_TRUE(expected.Equals(map.Get(kPolicyHomepageLocation))); + map.Set(kPolicyHomepageLocation, Value::CreateStringValue("bbb")); + StringValue expected_b("bbb"); + EXPECT_TRUE(expected_b.Equals(map.Get(kPolicyHomepageLocation))); +} + +TEST(PolicyMapTest, Equals) { + PolicyMap a; + a.Set(kPolicyHomepageLocation, Value::CreateStringValue("aaa")); + PolicyMap a2; + a2.Set(kPolicyHomepageLocation, Value::CreateStringValue("aaa")); + PolicyMap b; + b.Set(kPolicyHomepageLocation, Value::CreateStringValue("bbb")); + PolicyMap c; + c.Set(kPolicyHomepageLocation, Value::CreateStringValue("aaa")); + c.Set(kPolicyHomepageIsNewTabPage, Value::CreateBooleanValue(true)); + EXPECT_FALSE(a.Equals(b)); + EXPECT_FALSE(b.Equals(a)); + EXPECT_FALSE(a.Equals(c)); + EXPECT_FALSE(c.Equals(a)); + EXPECT_TRUE(a.Equals(a2)); + EXPECT_TRUE(a2.Equals(a)); + PolicyMap empty1; + PolicyMap empty2; + EXPECT_TRUE(empty1.Equals(empty2)); + EXPECT_TRUE(empty2.Equals(empty1)); + EXPECT_FALSE(empty1.Equals(a)); + EXPECT_FALSE(a.Equals(empty1)); +} + +TEST(PolicyMapTest, Swap) { + PolicyMap a; + a.Set(kPolicyHomepageLocation, Value::CreateStringValue("aaa")); + PolicyMap b; + b.Set(kPolicyHomepageLocation, Value::CreateStringValue("bbb")); + b.Set(kPolicyHomepageIsNewTabPage, Value::CreateBooleanValue(true)); + a.Swap(&b); + StringValue expected("bbb"); + EXPECT_TRUE(expected.Equals(a.Get(kPolicyHomepageLocation))); + FundamentalValue expected_bool(true); + EXPECT_TRUE(expected_bool.Equals(a.Get(kPolicyHomepageIsNewTabPage))); + StringValue expected_a("aaa"); + EXPECT_TRUE(expected_a.Equals(b.Get(kPolicyHomepageLocation))); + + b.Clear(); + a.Swap(&b); + PolicyMap empty; + EXPECT_TRUE(a.Equals(empty)); + EXPECT_FALSE(b.Equals(empty)); +} + +} // namespace policy diff --git a/chrome/browser/policy/profile_policy_context.cc b/chrome/browser/policy/profile_policy_context.cc index 7adffd3..b8e3151a 100644 --- a/chrome/browser/policy/profile_policy_context.cc +++ b/chrome/browser/policy/profile_policy_context.cc @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> +#include <string> + #include "base/command_line.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/device_management_policy_provider.h" @@ -20,7 +23,7 @@ namespace { const int64 kPolicyRefreshRateMinMs = 30 * 60 * 1000; // 30 minutes const int64 kPolicyRefreshRateMaxMs = 24 * 60 * 60 * 1000; // 1 day -} +} // namespace namespace policy { diff --git a/chrome/browser/policy/proto/cloud_policy.proto b/chrome/browser/policy/proto/cloud_policy.proto deleted file mode 100644 index 82a1135..0000000 --- a/chrome/browser/policy/proto/cloud_policy.proto +++ /dev/null @@ -1,221 +0,0 @@ -// -// DO NOT MODIFY THIS FILE DIRECTLY! -// ITS IS GENERATED BY generate_policy_source.py -// FROM policy_templates.json -// - -syntax = "proto2"; - -option optimize_for = LITE_RUNTIME; - -package enterprise_management; - -// PBs for individual settings. - -message PolicyOptions { - enum PolicyMode { - // The user may choose to override the given settings. - RECOMMENDED = 1; - // The given settings are applied regardless of user choice. - MANDATORY = 2; - } - optional PolicyMode mode = 1; -} - -message HomepageProto { - optional PolicyOptions policy_options = 1; - optional string HomepageLocation = 2; - optional bool HomepageIsNewTabPage = 3; -} - -message ApplicationLocaleValueProto { - optional PolicyOptions policy_options = 1; - optional string ApplicationLocaleValue = 2; -} - -message AlternateErrorPagesEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool AlternateErrorPagesEnabled = 2; -} - -message SearchSuggestEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool SearchSuggestEnabled = 2; -} - -message DnsPrefetchingEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool DnsPrefetchingEnabled = 2; -} - -message DisableSpdyProto { - optional PolicyOptions policy_options = 1; - optional bool DisableSpdy = 2; -} - -message JavascriptEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool JavascriptEnabled = 2; -} - -message SavingBrowserHistoryDisabledProto { - optional PolicyOptions policy_options = 1; - optional bool SavingBrowserHistoryDisabled = 2; -} - -message PrintingEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool PrintingEnabled = 2; -} - -message SafeBrowsingEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool SafeBrowsingEnabled = 2; -} - -message MetricsReportingEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool MetricsReportingEnabled = 2; -} - -message PasswordManagerProto { - optional PolicyOptions policy_options = 1; - optional bool PasswordManagerEnabled = 2; - optional bool PasswordManagerAllowShowPasswords = 3; -} - -message AutoFillEnabledProto { - optional PolicyOptions policy_options = 1; - optional bool AutoFillEnabled = 2; -} - -message DisabledPluginsProto { - optional PolicyOptions policy_options = 1; - repeated string DisabledPlugins = 2; -} - -message SyncDisabledProto { - optional PolicyOptions policy_options = 1; - optional bool SyncDisabled = 2; -} - -message ProxyProto { - optional PolicyOptions policy_options = 1; - optional string ProxyMode = 2; - optional int64 ProxyServerMode = 3; - optional string ProxyServer = 4; - optional string ProxyPacUrl = 5; - optional string ProxyBypassList = 6; -} - -message HTTPAuthenticationProto { - optional PolicyOptions policy_options = 1; - optional string AuthSchemes = 2; - optional bool DisableAuthNegotiateCnameLookup = 3; - optional bool EnableAuthNegotiatePort = 4; - optional string AuthServerWhitelist = 5; - optional string AuthNegotiateDelegateWhitelist = 6; - optional string GSSAPILibraryName = 7; -} - -message ExtensionsProto { - optional PolicyOptions policy_options = 1; - repeated string ExtensionInstallBlacklist = 2; - repeated string ExtensionInstallWhitelist = 3; - repeated string ExtensionInstallForcelist = 4; -} - -message ShowHomeButtonProto { - optional PolicyOptions policy_options = 1; - optional bool ShowHomeButton = 2; -} - -message DeveloperToolsDisabledProto { - optional PolicyOptions policy_options = 1; - optional bool DeveloperToolsDisabled = 2; -} - -message RestoreOnStartupGroupProto { - optional PolicyOptions policy_options = 1; - optional int64 RestoreOnStartup = 2; - repeated string RestoreOnStartupURLs = 3; -} - -message DefaultSearchProviderProto { - optional PolicyOptions policy_options = 1; - optional bool DefaultSearchProviderEnabled = 2; - optional string DefaultSearchProviderName = 3; - optional string DefaultSearchProviderKeyword = 4; - optional string DefaultSearchProviderSearchURL = 5; - optional string DefaultSearchProviderSuggestURL = 6; - optional string DefaultSearchProviderInstantURL = 7; - optional string DefaultSearchProviderIconURL = 8; - repeated string DefaultSearchProviderEncodings = 9; -} - -message ContentSettingsProto { - optional PolicyOptions policy_options = 1; - optional int64 DefaultCookiesSetting = 2; - optional int64 DefaultImagesSetting = 3; - optional int64 DefaultJavaScriptSetting = 4; - optional int64 DefaultPluginsSetting = 5; - optional int64 DefaultPopupsSetting = 6; - optional int64 DefaultNotificationSetting = 7; - optional int64 DefaultGeolocationSetting = 8; -} - -message Disable3DAPIsProto { - optional PolicyOptions policy_options = 1; - optional bool Disable3DAPIs = 2; -} - -message ChromeFrameRendererSettingsProto { - optional PolicyOptions policy_options = 1; - optional int64 ChromeFrameRendererSettings = 2; - repeated string RenderInChromeFrameList = 3; - repeated string RenderInHostList = 4; -} - -message ChromeFrameContentTypesProto { - optional PolicyOptions policy_options = 1; - repeated string ChromeFrameContentTypes = 2; -} - -message ChromeOsLockOnIdleSuspendProto { - optional PolicyOptions policy_options = 1; - optional bool ChromeOsLockOnIdleSuspend = 2; -} - - -// -------------------------------------------------- -// Wrapper PB for DMServer -> ChromeOS communication. - -message CloudPolicySettings { - optional HomepageProto Homepage = 1; - optional ApplicationLocaleValueProto ApplicationLocaleValue = 2; - optional AlternateErrorPagesEnabledProto AlternateErrorPagesEnabled = 3; - optional SearchSuggestEnabledProto SearchSuggestEnabled = 4; - optional DnsPrefetchingEnabledProto DnsPrefetchingEnabled = 5; - optional DisableSpdyProto DisableSpdy = 6; - optional JavascriptEnabledProto JavascriptEnabled = 7; - optional SavingBrowserHistoryDisabledProto SavingBrowserHistoryDisabled = 8; - optional PrintingEnabledProto PrintingEnabled = 9; - optional SafeBrowsingEnabledProto SafeBrowsingEnabled = 10; - optional MetricsReportingEnabledProto MetricsReportingEnabled = 11; - optional PasswordManagerProto PasswordManager = 12; - optional AutoFillEnabledProto AutoFillEnabled = 13; - optional DisabledPluginsProto DisabledPlugins = 14; - optional SyncDisabledProto SyncDisabled = 15; - optional ProxyProto Proxy = 16; - optional HTTPAuthenticationProto HTTPAuthentication = 17; - optional ExtensionsProto Extensions = 18; - optional ShowHomeButtonProto ShowHomeButton = 19; - optional DeveloperToolsDisabledProto DeveloperToolsDisabled = 20; - optional RestoreOnStartupGroupProto RestoreOnStartupGroup = 21; - optional DefaultSearchProviderProto DefaultSearchProvider = 22; - optional ContentSettingsProto ContentSettings = 23; - optional Disable3DAPIsProto Disable3DAPIs = 24; - optional ChromeFrameRendererSettingsProto ChromeFrameRendererSettings = 25; - optional ChromeFrameContentTypesProto ChromeFrameContentTypes = 26; - optional ChromeOsLockOnIdleSuspendProto ChromeOsLockOnIdleSuspend = 27; -} diff --git a/chrome/browser/policy/proto/device_management_backend.proto b/chrome/browser/policy/proto/device_management_backend.proto index 3187f6b..1a857b6 100644 --- a/chrome/browser/policy/proto/device_management_backend.proto +++ b/chrome/browser/policy/proto/device_management_backend.proto @@ -88,62 +88,94 @@ message DevicePolicyResponse { repeated DevicePolicySetting setting = 1; } +// Request from device to server to register device. The response will include +// a device token that can be used to query policies. +message DeviceRegisterRequest { + // reregister device without erasing server state. + // it can be used to refresh dmtoken etc. + optional bool reregister = 1; +} + +// Response from server to device register request. +message DeviceRegisterResponse { + // device mangement toke for this registration. + required string device_management_token = 1; +} + // Protocol buffers for the new protocol: // -------------------------------------- -// Request from device to server to query if the authenticated user is in a -// managed domain. -message ManagedCheckRequest { +// Request from device to server to get policies for an unregistered user. +// These are actually "meta-policies", that control the rules for the user +// about enrolling for real policies. +message InitialPolicyRequest { } -// Response from server to device indicating if the authenticated user is in a -// managed domain. -message ManagedCheckResponse { - enum Mode { - // The device must be enrolled for policies. +message InitialPolicySettings { + enum EnrollmentRule { + // The user must enroll its device for policies. MANAGED = 1; - // The device is not automatically enrolled for policies, but the user - // may choose to try to enroll it. + // The users's device is not automatically enrolled for policies, but the + // user may choose to try to enroll it. UNMANAGED = 2; } - optional Mode mode = 1; + optional EnrollmentRule enrollment_rule = 1; } -// Request from device to server to register device. -message DeviceRegisterRequest { - // reregister device without erasing server state. - // it can be used to refresh dmtoken etc. - optional bool reregister = 1; +// Response from server to device containing the policies available before +// registration. +message InitialPolicyResponse { + optional InitialPolicySettings settings = 1; } -// Response from server to device register request. -message DeviceRegisterResponse { - // device mangement toke for this registration. - required string device_management_token = 1; +// Request from device to server to unregister device management token. +message DeviceUnregisterRequest { +} - // The name of the device, assigned by the server. - optional string device_name = 2; +// Response from server to unregister request. +message DeviceUnregisterResponse { } -// Request from device to server to unregister device. -message DeviceUnregisterRequest { +// Request from device to server to register device. The response will include +// a device token that can be used to query policies. +message CloudRegisterRequest { + enum Type { + // Requesting token for user policies. + USER = 1; + // Requesting token for device policies. + DEVICE = 2; + } + optional Type type = 1; + // Unique identifier of the machine. Only set if type == DEVICE. + // This won't be sent in later requests, the machine can be identified + // by its device token. + optional string machine_id = 2; } -// Response from server to device unregister request. -message DeviceUnregisterResponse { +// Response from server to device register request. +message CloudRegisterResponse { + // Token for this registration. + required string device_management_token = 1; + + // The name of the requesting device, assigned by the server. + optional string machine_name = 2; } message CloudPolicyRequest { // Identify request scope: chromeos/device for device policies, chromeos/user - // for user policies. + // for user policies. Only those policy scopes will be served, that are + // allowed by the type choice in CloudRegisterRequest. optional string policy_scope = 1; - // The device token of the owner of the device sending the request. In cases - // the request was sent by the device owner or device policies were - // requested, this is the same as the token used for authentication. - // Otherwise (if the user policy is requested for someone else than the device - // owner) this token is different from the token used for authentication. - optional string device_token = 2; + + // The token used to query device policies on the device sending the request. + // Note, that the token used for actual authentication is sent in an HTTP + // header. These two tokens are the same if this request is for querying + // device policies and they differ if this request is for querying user + // policies. In the second case, the server can use device_policy_token to + // identify the device and determine if the user is allowed to get policies + // on the given device. + optional string device_policy_token = 2; } // Response from server to device for reading policies. @@ -176,20 +208,20 @@ message SignedCloudPolicyResponse { // // Http Query parameters: // Query parameters contain the following information in each request: -// request: register/unregister/policy/cloud_policy/managed_check etc. +// request: register/unregister/policy/cloud_policy/cloud_register/ +// initial_policy // devicetype: CrOS/Android/Iphone etc. // apptype: CrOS/AndroidDM etc. -// deviceid: unique id that identify the device. // agent: identify agent on device. // // Authorization: -// 1. If request is managed_check, client must pass in GoogleLogin auth -// cookie in Authorization header: +// 1. If request is initial_policy, client must pass in GoogleLogin +// auth cookie in Authorization header: // Authorization: GoogleLogin auth=<auth cookie> -// This is the only case when the deviceid query parameter is set to empty. -// The response will contain a flag indicating if the user is in a managed -// domain or not. (We don't want to expose device ids of users not in -// managed domains.) +// The response will contain settings that a user can get without +// registration. Currently the only such setting is a flag indicating if the +// user is in a managed domain or not. (We don't want to expose device ids of +// users not in managed domains.) // 2. If request is register_request, client must pass in GoogleLogin auth // cookie in Authorization header: // Authorization: GoogleLogin auth=<auth cookie> @@ -200,7 +232,7 @@ message SignedCloudPolicyResponse { // Authorization: GoogleDMToken token=<google dm token> // message DeviceManagementRequest { - // Register request. + // Register request (old protocol). optional DeviceRegisterRequest register_request = 1; // Unregister request. @@ -212,8 +244,11 @@ message DeviceManagementRequest { // Data request (new protocol). optional CloudPolicyRequest cloud_policy_request = 4; - // Request to check if a user is managed or not. - optional ManagedCheckRequest managed_check_request = 5; + // Request for initial (before registration) policies. + optional InitialPolicyRequest initial_policy_request = 5; + + // Register request (new protocol). + optional CloudRegisterRequest cloud_register_request = 6; } // Response from server to device. @@ -241,7 +276,7 @@ message DeviceManagementResponse { // Error message. optional string error_message = 2; - // Register response + // Register response (old protocol). optional DeviceRegisterResponse register_response = 3; // Unregister response @@ -253,6 +288,9 @@ message DeviceManagementResponse { // Policy response (new protocol). optional CloudPolicyResponse cloud_policy_response = 6; - // Response to managed check request. - optional ManagedCheckResponse managed_check_response = 7; + // Response to initial (before registration) policy request. + optional InitialPolicyResponse initial_policy_response = 7; + + // Register response (new protocol). + optional CloudRegisterResponse cloud_register_response = 8; }
\ No newline at end of file diff --git a/chrome/browser/policy/proto/device_management_local.proto b/chrome/browser/policy/proto/device_management_local.proto index a991551..45c2994 100644 --- a/chrome/browser/policy/proto/device_management_local.proto +++ b/chrome/browser/policy/proto/device_management_local.proto @@ -10,14 +10,18 @@ package enterprise_management; import "device_management_backend.proto"; -// Wrapper around DevicePolicyResponse for caching on disk. -message CachedDevicePolicyResponse { +// Wrapper around CloudPolicyResponse/DevicePolicyResponse for caching on disk. +message CachedCloudPolicyResponse { // The DevicePolicyResponse wrapped by this message. - optional DevicePolicyResponse policy = 1; - // Timestamp noting when this policy was cached. + optional DevicePolicyResponse device_policy = 1; + // Timestamp noting when the |unmanaged| flag was set. The data format is + // a unix timestamp. When caching (deprecated) DevicePolicyResponses, this + // timestamp also notes when the response was cached. optional uint64 timestamp = 2; // Flag that is set to true if this device is not managed. optional bool unmanaged = 3; + // The CloudPolicyResponse wrapped by this message. + optional CloudPolicyResponse cloud_policy = 4; } // Encapsulates a device ID and the associated device token. diff --git a/chrome/browser/policy/proto/device_management_proto.gyp b/chrome/browser/policy/proto/device_management_proto.gyp deleted file mode 100644 index ede0251..0000000 --- a/chrome/browser/policy/proto/device_management_proto.gyp +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) 2010 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. - -{ - 'variables': { - 'chromium_code': 1, - 'protoc_out_dir': '<(SHARED_INTERMEDIATE_DIR)/protoc_out', - }, - 'targets': [ - { - # Protobuf compiler / generate rule for the device management protocol. - 'target_name': 'device_management_proto', - 'type': 'none', - 'sources': [ - 'cloud_policy.proto', - 'device_management_backend.proto', - 'device_management_local.proto', - ], - 'rules': [ - { - 'rule_name': 'genproto', - 'extension': 'proto', - 'inputs': [ - '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', - ], - 'variables': { - # The protoc compiler requires a proto_path argument with the - # directory containing the .proto file. There's no generator - # variable that corresponds to this, so fake it. - 'rule_input_relpath': 'chrome/browser/policy/proto', - }, - 'outputs': [ - '<(PRODUCT_DIR)/pyproto/device_management_pb/<(RULE_INPUT_ROOT)_pb2.py', - '<(protoc_out_dir)/<(rule_input_relpath)/<(RULE_INPUT_ROOT).pb.h', - '<(protoc_out_dir)/<(rule_input_relpath)/<(RULE_INPUT_ROOT).pb.cc', - ], - 'action': [ - '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', - '--proto_path=.', - './<(RULE_INPUT_ROOT)<(RULE_INPUT_EXT)', - '--cpp_out=<(protoc_out_dir)/<(rule_input_relpath)', - '--python_out=<(PRODUCT_DIR)/pyproto/device_management_pb', - ], - 'message': 'Generating C++ and Python code from <(RULE_INPUT_PATH)', - }, - ], - 'dependencies': [ - '../../../../third_party/protobuf/protobuf.gyp:protoc#host', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(protoc_out_dir)', - ] - }, - }, - { - 'target_name': 'device_management_proto_cpp', - 'type': 'none', - 'export_dependent_settings': [ - '../../../../third_party/protobuf/protobuf.gyp:protobuf_lite', - 'device_management_proto', - ], - 'dependencies': [ - '../../../../third_party/protobuf/protobuf.gyp:protobuf_lite', - 'device_management_proto', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(protoc_out_dir)', - ] - }, - }, - ], -} - -# Local Variables: -# tab-width:2 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=2 shiftwidth=2: |