diff options
Diffstat (limited to 'chrome/browser/policy')
49 files changed, 2686 insertions, 1860 deletions
diff --git a/chrome/browser/policy/asynchronous_policy_loader.cc b/chrome/browser/policy/asynchronous_policy_loader.cc new file mode 100644 index 0000000..6ccae7a --- /dev/null +++ b/chrome/browser/policy/asynchronous_policy_loader.cc @@ -0,0 +1,158 @@ +// 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/asynchronous_policy_loader.h" + +#include "base/message_loop.h" +#include "base/task.h" +#include "chrome/browser/browser_thread.h" + +namespace policy { + +AsynchronousPolicyLoader::AsynchronousPolicyLoader( + AsynchronousPolicyProvider::Delegate* delegate, + int reload_interval_minutes) + : delegate_(delegate), + reload_task_(NULL), + reload_interval_(base::TimeDelta::FromMinutes(reload_interval_minutes)), + origin_loop_(MessageLoop::current()), + stopped_(false) {} + +void AsynchronousPolicyLoader::Init() { + policy_.reset(delegate_->Load()); + // Initialization can happen early when the file thread is not yet available, + // but the subclass of the loader must do some of their initialization on the + // file thread. Posting to the file thread directly before it is initialized + // will cause the task to be forgotten. Instead, post a task to the ui thread + // to delay the remainder of initialization until threading is fully + // initialized. + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod( + this, + &AsynchronousPolicyLoader::InitAfterFileThreadAvailable)); +} + +void AsynchronousPolicyLoader::Stop() { + if (!stopped_) { + stopped_ = true; + delegate_.reset(); + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod(this, &AsynchronousPolicyLoader::StopOnFileThread)); + } +} + +AsynchronousPolicyLoader::~AsynchronousPolicyLoader() { +} + +// Manages the life cycle of a new policy map during until its life cycle is +// taken over by the policy loader. +class UpdatePolicyTask : public Task { + public: + UpdatePolicyTask(scoped_refptr<AsynchronousPolicyLoader> loader, + DictionaryValue* new_policy) + : loader_(loader), + new_policy_(new_policy) {} + + virtual void Run() { + loader_->UpdatePolicy(new_policy_.release()); + } + + private: + scoped_refptr<AsynchronousPolicyLoader> loader_; + scoped_ptr<DictionaryValue> new_policy_; + DISALLOW_COPY_AND_ASSIGN(UpdatePolicyTask); +}; + +void AsynchronousPolicyLoader::Reload() { + if (delegate_.get()) { + DictionaryValue* new_policy = delegate_->Load(); + PostUpdatePolicyTask(new_policy); + } +} + +void AsynchronousPolicyLoader::AddObserver( + ConfigurationPolicyProvider::Observer* observer) { + observer_list_.AddObserver(observer); +} + +void AsynchronousPolicyLoader::RemoveObserver( + ConfigurationPolicyProvider::Observer* observer) { + observer_list_.RemoveObserver(observer); +} + +void AsynchronousPolicyLoader::CancelReloadTask() { + if (reload_task_) { + // Only check the thread if there's still a reload task. During + // destruction of unit tests, the message loop destruction can + // call this method when the file thread is no longer around, + // but in that case reload_task_ is NULL. + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + reload_task_->Cancel(); + reload_task_ = NULL; + } +} + +void AsynchronousPolicyLoader::ScheduleReloadTask( + const base::TimeDelta& delay) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + CancelReloadTask(); + + reload_task_ = + NewRunnableMethod(this, &AsynchronousPolicyLoader::ReloadFromTask); + BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_, + delay.InMilliseconds()); +} + +void AsynchronousPolicyLoader::ScheduleFallbackReloadTask() { + // As a safeguard in case that the load delegate failed to timely notice a + // change in policy, schedule a reload task that'll make us recheck after a + // reasonable interval. + ScheduleReloadTask(reload_interval_); +} + +void AsynchronousPolicyLoader::ReloadFromTask() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + // Drop the reference to the reload task, since the task might be the only + // referrer that keeps us alive, so we should not Cancel() it. + reload_task_ = NULL; + + Reload(); +} + +void AsynchronousPolicyLoader::InitOnFileThread() { +} + +void AsynchronousPolicyLoader::StopOnFileThread() { + CancelReloadTask(); +} + +void AsynchronousPolicyLoader::PostUpdatePolicyTask( + DictionaryValue* new_policy) { + origin_loop_->PostTask(FROM_HERE, new UpdatePolicyTask(this, new_policy)); +} + +void AsynchronousPolicyLoader::UpdatePolicy(DictionaryValue* new_policy_raw) { + scoped_ptr<DictionaryValue> new_policy(new_policy_raw); + DCHECK(policy_.get()); + if (!policy_->Equals(new_policy.get())) { + policy_.reset(new_policy.release()); + FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, + observer_list_, + OnUpdatePolicy()); + } +} + +void AsynchronousPolicyLoader::InitAfterFileThreadAvailable() { + if (!stopped_) { + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod(this, &AsynchronousPolicyLoader::InitOnFileThread)); + } +} + +} // namespace policy diff --git a/chrome/browser/policy/asynchronous_policy_loader.h b/chrome/browser/policy/asynchronous_policy_loader.h new file mode 100644 index 0000000..677ce6f --- /dev/null +++ b/chrome/browser/policy/asynchronous_policy_loader.h @@ -0,0 +1,118 @@ +// 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. + +#ifndef CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_LOADER_H_ +#define CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_LOADER_H_ +#pragma once + +#include "base/message_loop.h" +#include "base/observer_list.h" +#include "base/ref_counted.h" +#include "base/values.h" +#include "chrome/browser/policy/asynchronous_policy_provider.h" +#include "chrome/browser/policy/configuration_policy_provider.h" + +namespace policy { + +// Used by the implementation of asynchronous policy provider to manage the +// tasks on the file thread that do the heavy lifting of loading policies. +class AsynchronousPolicyLoader + : public base::RefCountedThreadSafe<AsynchronousPolicyLoader> { + public: + explicit AsynchronousPolicyLoader( + AsynchronousPolicyProvider::Delegate* delegate, + int reload_interval_minutes); + + // Triggers initial policy load. + virtual void Init(); + + // Reloads policy, sending notification of changes if necessary. Must be + // called on the file thread. + virtual void Reload(); + + // Stops any pending reload tasks. + virtual void Stop(); + + void AddObserver(ConfigurationPolicyProvider::Observer* observer); + void RemoveObserver(ConfigurationPolicyProvider::Observer* observer); + + const DictionaryValue* policy() const { return policy_.get(); } + + protected: + friend class UpdatePolicyTask; + + // AsynchronousPolicyLoader objects should only be deleted by + // RefCountedThreadSafe. + friend class base::RefCountedThreadSafe<AsynchronousPolicyLoader>; + virtual ~AsynchronousPolicyLoader(); + + // Schedules a call to UpdatePolicy on |origin_loop_|. Takes ownership of + // |new_policy|. + void PostUpdatePolicyTask(DictionaryValue* new_policy); + + AsynchronousPolicyProvider::Delegate* delegate() { + return delegate_.get(); + } + + // Performs start operations that must be performed on the file thread. + virtual void InitOnFileThread(); + + // Performs stop operations that must be performed on the file thread. + virtual void StopOnFileThread(); + + // Schedules a reload task to run when |delay| expires. Must be called on the + // file thread. + void ScheduleReloadTask(const base::TimeDelta& delay); + + // Schedules a reload task to run after the number of minutes specified + // in |reload_interval_minutes_|. Must be called on the file thread. + void ScheduleFallbackReloadTask(); + + void CancelReloadTask(); + + // Invoked from the reload task on the file thread. + void ReloadFromTask(); + + private: + friend class AsynchronousPolicyLoaderTest; + + // Finishes loader initialization after the threading system has been fully + // intialized. + void InitAfterFileThreadAvailable(); + + // Replaces the existing policy to value map with a new one, sending + // notification to the observers if there is a policy change. Must be called + // on |origin_loop_| so that it's safe to call back into the provider, which + // is not thread-safe. Takes ownership of |new_policy|. + void UpdatePolicy(DictionaryValue* new_policy); + + // Provides the low-level mechanics for loading policy. + scoped_ptr<AsynchronousPolicyProvider::Delegate> delegate_; + + // Current policy. + scoped_ptr<DictionaryValue> policy_; + + // The reload task. Access only on the file thread. Holds a reference to the + // currently posted task, so we can cancel and repost it if necessary. + CancelableTask* reload_task_; + + // The interval at which a policy reload will be triggered as a fallback. + const base::TimeDelta reload_interval_; + + // The message loop on which this object was constructed. Recorded so that + // it's possible to call back into the non thread safe provider to fire the + // notification. + MessageLoop* origin_loop_; + + // True if Stop has been called. + bool stopped_; + + ObserverList<ConfigurationPolicyProvider::Observer, true> observer_list_; + + DISALLOW_COPY_AND_ASSIGN(AsynchronousPolicyLoader); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_LOADER_H_ diff --git a/chrome/browser/policy/asynchronous_policy_loader_unittest.cc b/chrome/browser/policy/asynchronous_policy_loader_unittest.cc new file mode 100644 index 0000000..3cc416c --- /dev/null +++ b/chrome/browser/policy/asynchronous_policy_loader_unittest.cc @@ -0,0 +1,134 @@ +// 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/asynchronous_policy_loader.h" +#include "chrome/browser/policy/asynchronous_policy_provider.h" +#include "chrome/browser/policy/asynchronous_policy_test_base.h" +#include "chrome/browser/policy/mock_configuration_policy_provider.h" +#include "testing/gmock/include/gmock/gmock.h" + +using ::testing::_; +using ::testing::InSequence; +using ::testing::Return; + +namespace policy { + +class MockConfigurationPolicyObserver + : public ConfigurationPolicyProvider::Observer { + public: + MOCK_METHOD0(OnUpdatePolicy, void()); +}; + +class AsynchronousPolicyLoaderTest : public AsynchronousPolicyTestBase { + public: + AsynchronousPolicyLoaderTest() {} + virtual ~AsynchronousPolicyLoaderTest() {} + + virtual void SetUp() { + AsynchronousPolicyTestBase::SetUp(); + mock_provider_.reset(new MockConfigurationPolicyProvider()); + } + + protected: + scoped_ptr<MockConfigurationPolicyProvider> mock_provider_; + + private: + DISALLOW_COPY_AND_ASSIGN(AsynchronousPolicyLoaderTest); +}; + +ACTION(CreateTestDictionary) { + return new DictionaryValue(); +} + +ACTION_P(CreateSequencedTestDictionary, number) { + DictionaryValue* test_dictionary = new DictionaryValue(); + test_dictionary->SetInteger("id", ++(*number)); + return test_dictionary; +} + +ACTION(RescheduleImmediatePolicyReload) { + *arg1 = base::TimeDelta(); + return false; +} + +TEST_F(AsynchronousPolicyLoaderTest, InitialLoad) { + DictionaryValue* template_dict(new DictionaryValue()); + EXPECT_CALL(*delegate_, Load()).WillOnce(Return(template_dict)); + scoped_refptr<AsynchronousPolicyLoader> loader = + new AsynchronousPolicyLoader(delegate_.release(), 10); + loader->Init(); + const DictionaryValue* loaded_dict(loader->policy()); + EXPECT_TRUE(loaded_dict->Equals(template_dict)); +} + +// Verify that the fallback policy requests are made. +TEST_F(AsynchronousPolicyLoaderTest, InitialLoadWithFallback) { + int dictionary_number = 0; + InSequence s; + EXPECT_CALL(*delegate_, Load()).WillOnce( + CreateSequencedTestDictionary(&dictionary_number)); + EXPECT_CALL(*delegate_, Load()).WillOnce( + CreateSequencedTestDictionary(&dictionary_number)); + scoped_refptr<AsynchronousPolicyLoader> loader = + new AsynchronousPolicyLoader(delegate_.release(), 10); + loader->Init(); + loop_.RunAllPending(); + loader->Reload(); + loop_.RunAllPending(); + + const DictionaryValue* loaded_dict(loader->policy()); + int loaded_number; + EXPECT_TRUE(loaded_dict->GetInteger("id", &loaded_number)); + EXPECT_EQ(dictionary_number, loaded_number); +} + +// Ensure that calling stop on the loader stops subsequent reloads from +// happening. +TEST_F(AsynchronousPolicyLoaderTest, Stop) { + ON_CALL(*delegate_, Load()).WillByDefault(CreateTestDictionary()); + EXPECT_CALL(*delegate_, Load()).Times(1); + scoped_refptr<AsynchronousPolicyLoader> loader = + new AsynchronousPolicyLoader(delegate_.release(), 10); + loader->Init(); + loop_.RunAllPending(); + loader->Stop(); + loop_.RunAllPending(); + loader->Reload(); + loop_.RunAllPending(); +} + +// Verifies that the provider is notified upon policy reload, but only +// if the policy changed. +TEST_F(AsynchronousPolicyLoaderTest, ProviderNotificationOnPolicyChange) { + InSequence s; + MockConfigurationPolicyObserver observer; + int dictionary_number_1 = 0; + int dictionary_number_2 = 0; + EXPECT_CALL(*delegate_, Load()).WillOnce( + CreateSequencedTestDictionary(&dictionary_number_1)); + EXPECT_CALL(*delegate_, Load()).WillOnce( + CreateSequencedTestDictionary(&dictionary_number_2)); + EXPECT_CALL(observer, OnUpdatePolicy()).Times(0); + EXPECT_CALL(*delegate_, Load()).WillOnce( + CreateSequencedTestDictionary(&dictionary_number_2)); + EXPECT_CALL(observer, OnUpdatePolicy()).Times(1); + EXPECT_CALL(*delegate_, Load()).WillOnce( + CreateSequencedTestDictionary(&dictionary_number_1)); + scoped_refptr<AsynchronousPolicyLoader> loader = + new AsynchronousPolicyLoader(delegate_.release(), 10); + AsynchronousPolicyProvider provider(NULL, loader); + // |registrar| must be declared last so that it is destroyed first. + ConfigurationPolicyObserverRegistrar registrar; + registrar.Init(&provider); + registrar.AddObserver(&observer); + loop_.RunAllPending(); + loader->Reload(); + loop_.RunAllPending(); + loader->Reload(); + loop_.RunAllPending(); + loader->Reload(); + loop_.RunAllPending(); +} + +} // namespace policy diff --git a/chrome/browser/policy/asynchronous_policy_provider.cc b/chrome/browser/policy/asynchronous_policy_provider.cc new file mode 100644 index 0000000..e697b05 --- /dev/null +++ b/chrome/browser/policy/asynchronous_policy_provider.cc @@ -0,0 +1,46 @@ +// 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/asynchronous_policy_provider.h" + +#include "chrome/browser/policy/asynchronous_policy_loader.h" + +namespace policy { + +AsynchronousPolicyProvider::AsynchronousPolicyProvider( + const PolicyDefinitionList* policy_list, + scoped_refptr<AsynchronousPolicyLoader> loader) + : ConfigurationPolicyProvider(policy_list), + loader_(loader) { + loader_->Init(); +} + +AsynchronousPolicyProvider::~AsynchronousPolicyProvider() { + DCHECK(CalledOnValidThread()); + loader_->Stop(); +} + +bool AsynchronousPolicyProvider::Provide( + ConfigurationPolicyStoreInterface* store) { + DCHECK(CalledOnValidThread()); + DCHECK(loader_->policy()); + DecodePolicyValueTree(loader_->policy(), store); + return true; +} + +void AsynchronousPolicyProvider::AddObserver( + ConfigurationPolicyProvider::Observer* observer) { + loader_->AddObserver(observer); +} + +void AsynchronousPolicyProvider::RemoveObserver( + ConfigurationPolicyProvider::Observer* observer) { + loader_->RemoveObserver(observer); +} + +scoped_refptr<AsynchronousPolicyLoader> AsynchronousPolicyProvider::loader() { + return loader_; +} + +} // namespace policy diff --git a/chrome/browser/policy/asynchronous_policy_provider.h b/chrome/browser/policy/asynchronous_policy_provider.h new file mode 100644 index 0000000..561fc37 --- /dev/null +++ b/chrome/browser/policy/asynchronous_policy_provider.h @@ -0,0 +1,61 @@ +// 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. + +#ifndef CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_PROVIDER_H_ +#define CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_PROVIDER_H_ +#pragma once + +#include "base/non_thread_safe.h" +#include "base/ref_counted.h" +#include "base/weak_ptr.h" +#include "chrome/browser/policy/configuration_policy_provider.h" + +namespace policy { + +class AsynchronousPolicyLoader; + +// Policy provider that loads policy asynchronously. Providers should subclass +// from this class if loading the policy requires disk access or must for some +// other reason be performed on the file thread. The actual logic for loading +// policy is handled by a delegate passed at construction time. +class AsynchronousPolicyProvider + : public ConfigurationPolicyProvider, + public NonThreadSafe { + public: + // Must be implemented by subclasses of the asynchronous policy provider to + // provide the implementation details of how policy is loaded. + class Delegate { + public: + virtual ~Delegate() {} + + virtual DictionaryValue* Load() = 0; + }; + + // Assumes ownership of |loader|. + AsynchronousPolicyProvider( + const PolicyDefinitionList* policy_list, + scoped_refptr<AsynchronousPolicyLoader> loader); + virtual ~AsynchronousPolicyProvider(); + + // ConfigurationPolicyProvider implementation. + virtual bool Provide(ConfigurationPolicyStoreInterface* store); + + // For tests to trigger reloads. + scoped_refptr<AsynchronousPolicyLoader> loader(); + + protected: + // The loader object used internally. + scoped_refptr<AsynchronousPolicyLoader> loader_; + + private: + // ConfigurationPolicyProvider overrides: + virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer); + virtual void RemoveObserver(ConfigurationPolicyProvider::Observer* observer); + + DISALLOW_COPY_AND_ASSIGN(AsynchronousPolicyProvider); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_PROVIDER_H_ diff --git a/chrome/browser/policy/asynchronous_policy_provider_unittest.cc b/chrome/browser/policy/asynchronous_policy_provider_unittest.cc new file mode 100644 index 0000000..c6aee70 --- /dev/null +++ b/chrome/browser/policy/asynchronous_policy_provider_unittest.cc @@ -0,0 +1,57 @@ +// 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/asynchronous_policy_loader.h" +#include "chrome/browser/policy/asynchronous_policy_provider.h" +#include "chrome/browser/policy/asynchronous_policy_test_base.h" +#include "chrome/browser/policy/configuration_policy_pref_store.h" +#include "chrome/browser/policy/mock_configuration_policy_store.h" +#include "chrome/common/policy_constants.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; +using ::testing::InSequence; +using ::testing::Return; + +namespace policy { + +// Creating the provider should provide initial policy. +TEST_F(AsynchronousPolicyTestBase, Provide) { + InSequence s; + DictionaryValue* policies = new DictionaryValue(); + policies->SetBoolean(policy::key::kSyncDisabled, true); + EXPECT_CALL(*delegate_, Load()).WillOnce(Return(policies)); + EXPECT_CALL(*store_, Apply(policy::kPolicySyncDisabled, _)).Times(1); + AsynchronousPolicyProvider provider( + ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), + new AsynchronousPolicyLoader(delegate_.release(), 10)); + provider.Provide(store_.get()); +} + + +// Trigger a refresh manually and ensure that policy gets reloaded. +TEST_F(AsynchronousPolicyTestBase, ProvideAfterRefresh) { + InSequence s; + DictionaryValue* original_policies = new DictionaryValue(); + original_policies->SetBoolean(policy::key::kSyncDisabled, true); + EXPECT_CALL(*delegate_, Load()).WillOnce(Return(original_policies)); + DictionaryValue* refresh_policies = new DictionaryValue(); + refresh_policies->SetBoolean( + policy::key::kJavascriptEnabled, + true); + EXPECT_CALL(*delegate_, Load()).WillOnce(Return(refresh_policies)); + AsynchronousPolicyLoader* loader = + new AsynchronousPolicyLoader(delegate_.release(), 10); + AsynchronousPolicyProvider provider( + ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), + loader); + loop_.RunAllPending(); + loader->Reload(); + loop_.RunAllPending(); + EXPECT_CALL(*store_, Apply(policy::kPolicyJavascriptEnabled, _)).Times(1); + provider.Provide(store_.get()); +} + +} // namespace policy diff --git a/chrome/browser/policy/asynchronous_policy_test_base.h b/chrome/browser/policy/asynchronous_policy_test_base.h new file mode 100644 index 0000000..0281afd --- /dev/null +++ b/chrome/browser/policy/asynchronous_policy_test_base.h @@ -0,0 +1,64 @@ +// 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. + +#ifndef CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_TEST_BASE_H_ +#define CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_TEST_BASE_H_ +#pragma once + +#include "base/message_loop.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/asynchronous_policy_provider.h" +#include "chrome/browser/policy/mock_configuration_policy_store.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace policy { + +// A delegate for testing that can feed arbitrary information to the loader. +class ProviderDelegateMock : public AsynchronousPolicyProvider::Delegate { + public: + ProviderDelegateMock() : AsynchronousPolicyProvider::Delegate() {} + virtual ~ProviderDelegateMock() {} + + MOCK_METHOD0(Load, DictionaryValue*()); + + private: + DISALLOW_COPY_AND_ASSIGN(ProviderDelegateMock); +}; + +class AsynchronousPolicyTestBase : public testing::Test { + public: + AsynchronousPolicyTestBase() + : ui_thread_(BrowserThread::UI, &loop_), + file_thread_(BrowserThread::FILE, &loop_) {} + + virtual ~AsynchronousPolicyTestBase() {} + + virtual void SetUp() { + delegate_.reset(new ProviderDelegateMock()); + store_.reset(new MockConfigurationPolicyStore); + } + + virtual void TearDown() { + loop_.RunAllPending(); + } + + protected: + MessageLoop loop_; + + // The mocks that are used in the test must outlive the scope of the test + // because they still get accessed in the RunAllPending of the TearDown. + scoped_ptr<MockConfigurationPolicyStore> store_; + scoped_ptr<ProviderDelegateMock> delegate_; + + private: + BrowserThread ui_thread_; + BrowserThread file_thread_; + + DISALLOW_COPY_AND_ASSIGN(AsynchronousPolicyTestBase); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_TEST_BASE_H_ diff --git a/chrome/browser/policy/config_dir_policy_provider.cc b/chrome/browser/policy/config_dir_policy_provider.cc index f134aeb..fb2f6eb 100644 --- a/chrome/browser/policy/config_dir_policy_provider.cc +++ b/chrome/browser/policy/config_dir_policy_provider.cc @@ -12,11 +12,12 @@ namespace policy { -ConfigDirPolicyLoader::ConfigDirPolicyLoader(const FilePath& config_dir) - : FileBasedPolicyProvider::Delegate(config_dir) { +ConfigDirPolicyProviderDelegate::ConfigDirPolicyProviderDelegate( + const FilePath& config_dir) + : FileBasedPolicyProvider::ProviderDelegate(config_dir) { } -DictionaryValue* ConfigDirPolicyLoader::Load() { +DictionaryValue* ConfigDirPolicyProviderDelegate::Load() { // Enumerate the files and sort them lexicographically. std::set<FilePath> files; file_util::FileEnumerator file_enumerator(config_file_path(), false, @@ -49,7 +50,7 @@ DictionaryValue* ConfigDirPolicyLoader::Load() { return policy; } -base::Time ConfigDirPolicyLoader::GetLastModification() { +base::Time ConfigDirPolicyProviderDelegate::GetLastModification() { base::Time last_modification = base::Time(); base::PlatformFileInfo file_info; @@ -68,7 +69,7 @@ base::Time ConfigDirPolicyLoader::GetLastModification() { config_file = file_enumerator.Next()) { if (file_util::GetFileInfo(config_file, &file_info) && !file_info.is_directory) { - last_modification = std::min(last_modification, file_info.last_modified); + last_modification = std::max(last_modification, file_info.last_modified); } } @@ -78,8 +79,9 @@ base::Time ConfigDirPolicyLoader::GetLastModification() { ConfigDirPolicyProvider::ConfigDirPolicyProvider( const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list, const FilePath& config_dir) - : FileBasedPolicyProvider(policy_list, - new ConfigDirPolicyLoader(config_dir)) { + : FileBasedPolicyProvider( + policy_list, + new ConfigDirPolicyProviderDelegate(config_dir)) { } } // namespace policy diff --git a/chrome/browser/policy/config_dir_policy_provider.h b/chrome/browser/policy/config_dir_policy_provider.h index 6096513..3647489 100644 --- a/chrome/browser/policy/config_dir_policy_provider.h +++ b/chrome/browser/policy/config_dir_policy_provider.h @@ -10,23 +10,6 @@ namespace policy { -// A policy loader implementation backed by a set of files in a given directory. -// The files should contain JSON-formatted policy settings. They are merged -// together and the result is returned via the PolicyLoader interface. The files -// are consulted in lexicographic file name order, so the last value read takes -// precedence in case of preference key collisions. -class ConfigDirPolicyLoader : public FileBasedPolicyProvider::Delegate { - public: - explicit ConfigDirPolicyLoader(const FilePath& config_dir); - - // FileBasedPolicyLoader::Delegate implementation. - virtual DictionaryValue* Load(); - virtual base::Time GetLastModification(); - - private: - DISALLOW_COPY_AND_ASSIGN(ConfigDirPolicyLoader); -}; - // Policy provider backed by JSON files in a configuration directory. class ConfigDirPolicyProvider : public FileBasedPolicyProvider { public: @@ -38,6 +21,24 @@ class ConfigDirPolicyProvider : public FileBasedPolicyProvider { DISALLOW_COPY_AND_ASSIGN(ConfigDirPolicyProvider); }; +// A provider delegate implementation backed by a set of files in a given +// directory. The files should contain JSON-formatted policy settings. They are +// merged together and the result is returned via the ProviderDelegate +// interface. The files are consulted in lexicographic file name order, so the +// last value read takes precedence in case of preference key collisions. +class ConfigDirPolicyProviderDelegate + : public FileBasedPolicyProvider::ProviderDelegate { + public: + explicit ConfigDirPolicyProviderDelegate(const FilePath& config_dir); + + // FileBasedPolicyProvider::ProviderDelegate implementation. + virtual DictionaryValue* Load(); + virtual base::Time GetLastModification(); + + private: + DISALLOW_COPY_AND_ASSIGN(ConfigDirPolicyProviderDelegate); +}; + } // namespace policy #endif // CHROME_BROWSER_POLICY_CONFIG_DIR_POLICY_PROVIDER_H_ diff --git a/chrome/browser/policy/config_dir_policy_provider_unittest.cc b/chrome/browser/policy/config_dir_policy_provider_unittest.cc index 25893da..8b7e9a0 100644 --- a/chrome/browser/policy/config_dir_policy_provider_unittest.cc +++ b/chrome/browser/policy/config_dir_policy_provider_unittest.cc @@ -8,6 +8,7 @@ #include "base/path_service.h" #include "base/scoped_temp_dir.h" #include "base/string_number_conversions.h" +#include "chrome/browser/browser_thread.h" #include "chrome/browser/policy/config_dir_policy_provider.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/mock_configuration_policy_store.h" @@ -49,7 +50,7 @@ class ConfigDirPolicyLoaderTest // The preferences dictionary is expected to be empty when there are no files to // load. TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsEmpty) { - ConfigDirPolicyLoader loader(test_dir()); + ConfigDirPolicyProviderDelegate loader(test_dir()); scoped_ptr<DictionaryValue> policy(loader.Load()); EXPECT_TRUE(policy.get()); EXPECT_TRUE(policy->empty()); @@ -59,7 +60,7 @@ TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsEmpty) { // dictionary. TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsNonExistentDirectory) { FilePath non_existent_dir(test_dir().Append(FILE_PATH_LITERAL("not_there"))); - ConfigDirPolicyLoader loader(non_existent_dir); + ConfigDirPolicyProviderDelegate loader(non_existent_dir); scoped_ptr<DictionaryValue> policy(loader.Load()); EXPECT_TRUE(policy.get()); EXPECT_TRUE(policy->empty()); @@ -71,7 +72,7 @@ TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsSinglePref) { test_dict.SetString("HomepageLocation", "http://www.google.com"); WriteConfigFile(test_dict, "config_file"); - ConfigDirPolicyLoader loader(test_dir()); + ConfigDirPolicyProviderDelegate loader(test_dir()); scoped_ptr<DictionaryValue> policy(loader.Load()); EXPECT_TRUE(policy.get()); EXPECT_TRUE(policy->Equals(&test_dict)); @@ -93,7 +94,7 @@ TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsMergePrefs) { for (unsigned int i = 5; i <= 8; ++i) WriteConfigFile(test_dict_bar, base::IntToString(i)); - ConfigDirPolicyLoader loader(test_dir()); + ConfigDirPolicyProviderDelegate loader(test_dir()); scoped_ptr<DictionaryValue> policy(loader.Load()); EXPECT_TRUE(policy.get()); EXPECT_TRUE(policy->Equals(&test_dict_foo)); @@ -258,8 +259,8 @@ INSTANTIATE_TEST_CASE_P( kPolicyDefaultSearchProviderEncodings, key::kDefaultSearchProviderEncodings), ValueTestParams::ForIntegerPolicy( - kPolicyProxyServerMode, - key::kProxyServerMode), + kPolicyProxyMode, + key::kProxyMode), ValueTestParams::ForStringPolicy( kPolicyProxyServer, key::kProxyServer), diff --git a/chrome/browser/policy/configuration_policy_loader_win.cc b/chrome/browser/policy/configuration_policy_loader_win.cc new file mode 100644 index 0000000..68ccf80 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_loader_win.cc @@ -0,0 +1,90 @@ +// 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/configuration_policy_loader_win.h" + +#include <userenv.h> + +#include "chrome/browser/browser_thread.h" + +namespace policy { + +ConfigurationPolicyLoaderWin::ConfigurationPolicyLoaderWin( + AsynchronousPolicyProvider::Delegate* delegate, + int reload_interval_minutes) + : AsynchronousPolicyLoader(delegate, reload_interval_minutes), + user_policy_changed_event_(false, false), + machine_policy_changed_event_(false, false), + user_policy_watcher_failed_(false), + machine_policy_watcher_failed_(false) { + if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) { + PLOG(WARNING) << "Failed to register user group policy notification"; + user_policy_watcher_failed_ = true; + } + if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) { + PLOG(WARNING) << "Failed to register machine group policy notification."; + machine_policy_watcher_failed_ = true; + } +} + +void ConfigurationPolicyLoaderWin::InitOnFileThread() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + AsynchronousPolicyLoader::InitOnFileThread(); + MessageLoop::current()->AddDestructionObserver(this); + SetupWatches(); +} + +void ConfigurationPolicyLoaderWin::StopOnFileThread() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + MessageLoop::current()->RemoveDestructionObserver(this); + user_policy_watcher_.StopWatching(); + machine_policy_watcher_.StopWatching(); + AsynchronousPolicyLoader::StopOnFileThread(); +} + +void ConfigurationPolicyLoaderWin::SetupWatches() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + CancelReloadTask(); + + if (!user_policy_watcher_failed_ && + !user_policy_watcher_.GetWatchedObject() && + !user_policy_watcher_.StartWatching( + user_policy_changed_event_.handle(), this)) { + LOG(WARNING) << "Failed to start watch for user policy change event"; + user_policy_watcher_failed_ = true; + } + if (!machine_policy_watcher_failed_ && + !machine_policy_watcher_.GetWatchedObject() && + !machine_policy_watcher_.StartWatching( + machine_policy_changed_event_.handle(), this)) { + LOG(WARNING) << "Failed to start watch for machine policy change event"; + machine_policy_watcher_failed_ = true; + } + + if (user_policy_watcher_failed_ || machine_policy_watcher_failed_) + ScheduleFallbackReloadTask(); +} + +void ConfigurationPolicyLoaderWin::Reload() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + AsynchronousPolicyLoader::Reload(); + SetupWatches(); +} + +void ConfigurationPolicyLoaderWin::OnObjectSignaled(HANDLE object) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + DCHECK(object == user_policy_changed_event_.handle() || + object == machine_policy_changed_event_.handle()) + << "unexpected object signaled policy reload, obj = " + << std::showbase << std::hex << object; + Reload(); +} + +void ConfigurationPolicyLoaderWin:: + WillDestroyCurrentMessageLoop() { + CancelReloadTask(); + MessageLoop::current()->RemoveDestructionObserver(this); +} + +} // namespace policy diff --git a/chrome/browser/policy/configuration_policy_loader_win.h b/chrome/browser/policy/configuration_policy_loader_win.h new file mode 100644 index 0000000..a898afc --- /dev/null +++ b/chrome/browser/policy/configuration_policy_loader_win.h @@ -0,0 +1,57 @@ +// 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. + +#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_LOADER_WIN_H_ +#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_LOADER_WIN_H_ +#pragma once + +#include "base/object_watcher.h" +#include "base/waitable_event.h" +#include "chrome/browser/policy/asynchronous_policy_loader.h" + +namespace policy { + +// Keeps watch on Windows Group Policy notification event to trigger a policy +// reload when Group Policy changes. +class ConfigurationPolicyLoaderWin + : public AsynchronousPolicyLoader, + public base::ObjectWatcher::Delegate, + public MessageLoop::DestructionObserver { + public: + ConfigurationPolicyLoaderWin( + AsynchronousPolicyProvider::Delegate* delegate, + int reload_interval_minutes); + virtual ~ConfigurationPolicyLoaderWin() {} + + protected: + // AsynchronousPolicyLoader overrides: + virtual void InitOnFileThread(); + virtual void StopOnFileThread(); + + private: + // Updates the watchers and schedules the reload task if appropriate. + void SetupWatches(); + + // Post a reload notification and update the watch machinery. + void Reload(); + + // ObjectWatcher::Delegate overrides: + virtual void OnObjectSignaled(HANDLE object); + + // MessageLoop::DestructionObserver overrides: + virtual void WillDestroyCurrentMessageLoop(); + + base::WaitableEvent user_policy_changed_event_; + base::WaitableEvent machine_policy_changed_event_; + base::ObjectWatcher user_policy_watcher_; + base::ObjectWatcher machine_policy_watcher_; + bool user_policy_watcher_failed_; + bool machine_policy_watcher_failed_; + + DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyLoaderWin); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_LOADER_WIN_H_ diff --git a/chrome/browser/policy/configuration_policy_pref_store.cc b/chrome/browser/policy/configuration_policy_pref_store.cc index 5a1eaaa..23e6510 100644 --- a/chrome/browser/policy/configuration_policy_pref_store.cc +++ b/chrome/browser/policy/configuration_policy_pref_store.cc @@ -4,15 +4,19 @@ #include "chrome/browser/policy/configuration_policy_pref_store.h" +#include <set> +#include <string> +#include <vector> + #include "base/command_line.h" +#include "base/lazy_instance.h" #include "base/logging.h" #include "base/path_service.h" -#include "base/singleton.h" +#include "base/stl_util-inl.h" #include "base/string16.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "base/values.h" -#include "chrome/browser/profile.h" #include "chrome/browser/policy/configuration_policy_provider.h" #if defined(OS_WIN) #include "chrome/browser/policy/configuration_policy_provider_win.h" @@ -24,98 +28,135 @@ #include "chrome/browser/policy/device_management_policy_provider.h" #include "chrome/browser/policy/dummy_configuration_policy_provider.h" #include "chrome/browser/policy/profile_policy_context.h" +#include "chrome/browser/prefs/pref_value_map.h" +#include "chrome/browser/prefs/proxy_prefs.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/search_terms_data.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_service.h" #include "chrome/common/policy_constants.h" #include "chrome/common/pref_names.h" namespace policy { -// Manages the lifecycle of the shared platform-specific policy providers for -// managed platform, device management and recommended policy. Instantiated as a -// Singleton. -class ConfigurationPolicyProviderKeeper { +// Accepts policy settings from a ConfigurationPolicyProvider, converts them +// to preferences and caches the result. +class ConfigurationPolicyPrefKeeper + : private ConfigurationPolicyStoreInterface { public: - ConfigurationPolicyProviderKeeper() - : managed_platform_provider_(CreateManagedPlatformProvider()), - device_management_provider_(CreateDeviceManagementProvider()), - recommended_provider_(CreateRecommendedProvider()) {} - virtual ~ConfigurationPolicyProviderKeeper() {} + explicit ConfigurationPolicyPrefKeeper(ConfigurationPolicyProvider* provider); + virtual ~ConfigurationPolicyPrefKeeper(); - ConfigurationPolicyProvider* managed_platform_provider() const { - return managed_platform_provider_.get(); - } - - ConfigurationPolicyProvider* device_management_provider() const { - return device_management_provider_.get(); - } + // Get a preference value. + PrefStore::ReadResult GetValue(const std::string& key, Value** result) const; - ConfigurationPolicyProvider* recommended_provider() const { - return recommended_provider_.get(); - } + // Compute the set of preference names that are different in |keeper|. This + // includes preferences that are missing in either one. + void GetDifferingPrefPaths(const ConfigurationPolicyPrefKeeper* other, + std::vector<std::string>* differing_prefs) const; private: - scoped_ptr<ConfigurationPolicyProvider> managed_platform_provider_; - scoped_ptr<ConfigurationPolicyProvider> device_management_provider_; - scoped_ptr<ConfigurationPolicyProvider> recommended_provider_; - - static ConfigurationPolicyProvider* CreateManagedPlatformProvider(); - static ConfigurationPolicyProvider* CreateDeviceManagementProvider(); - static ConfigurationPolicyProvider* CreateRecommendedProvider(); + // ConfigurationPolicyStore methods: + virtual void Apply(ConfigurationPolicyType setting, Value* value); + + // Policies that map to a single preference are handled + // by an automated converter. Each one of these policies + // has an entry in |simple_policy_map_| with the following type. + struct PolicyToPreferenceMapEntry { + Value::ValueType value_type; + ConfigurationPolicyType policy_type; + const char* preference_path; // A DictionaryValue path, not a file path. + }; - DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderKeeper); + // Returns the map entry that corresponds to |policy| in the map. + const PolicyToPreferenceMapEntry* FindPolicyInMap( + ConfigurationPolicyType policy, + const PolicyToPreferenceMapEntry* map, + int size) const; + + // Remove the preferences found in the map from |prefs_|. Returns true if any + // such preferences were found and removed. + bool RemovePreferencesOfMap(const PolicyToPreferenceMapEntry* map, + int table_size); + + bool ApplyPolicyFromMap(ConfigurationPolicyType policy, + Value* value, + const PolicyToPreferenceMapEntry* map, + int size); + + // Processes proxy-specific policies. Returns true if the specified policy + // is a proxy-related policy. ApplyProxyPolicy assumes the ownership + // of |value| in the case that the policy is proxy-specific. + bool ApplyProxyPolicy(ConfigurationPolicyType policy, Value* value); + + // Handles sync-related policies. Returns true if the policy was handled. + // Assumes ownership of |value| in that case. + bool ApplySyncPolicy(ConfigurationPolicyType policy, Value* value); + + // Handles policies that affect AutoFill. Returns true if the policy was + // handled and assumes ownership of |value| in that case. + bool ApplyAutoFillPolicy(ConfigurationPolicyType policy, Value* value); + + // Make sure that the |path| if present in |prefs_|. If not, set it to + // a blank string. + void EnsureStringPrefExists(const std::string& path); + + // If the required entries for default search are specified and valid, + // finalizes the policy-specified configuration by initializing the + // unspecified map entries. Otherwise wipes all default search related + // map entries from |prefs_|. + void FinalizeDefaultSearchPolicySettings(); + + // If the required entries for the proxy settings are specified and valid, + // finalizes the policy-specified configuration by initializing the + // respective values in |prefs_|. + void FinalizeProxyPolicySettings(); + + // Returns true if the policy values stored in proxy_* represent a valid + // proxy configuration. + bool CheckProxySettings(); + + // Assumes CheckProxySettings returns true and applies the values stored + // in proxy_*. + void ApplyProxySettings(); + + bool HasProxyPolicy(ConfigurationPolicyType policy) const; + + // Temporary cache that stores values until FinalizeProxyPolicySettings() + // is called. + std::map<ConfigurationPolicyType, Value*> proxy_policies_; + + // Set to false until the first proxy-relevant policy is applied. At that + // time, default values are provided for all proxy-relevant prefs + // to override any values set from stores with a lower priority. + bool lower_priority_proxy_settings_overridden_; + + // The following are used to track what proxy-relevant policy has been applied + // accross calls to Apply to provide a warning if a policy specifies a + // contradictory proxy configuration. |proxy_disabled_| is set to true if and + // only if the kPolicyNoProxyServer has been applied, + // |proxy_configuration_specified_| is set to true if and only if any other + // proxy policy other than kPolicyNoProxyServer has been applied. + bool proxy_disabled_; + bool proxy_configuration_specified_; + + // Set to true if a the proxy mode policy has been set to force Chrome + // to use the system proxy. + bool use_system_proxy_; + + PrefValueMap prefs_; + + static const PolicyToPreferenceMapEntry kSimplePolicyMap[]; + static const PolicyToPreferenceMapEntry kProxyPolicyMap[]; + static const PolicyToPreferenceMapEntry kDefaultSearchPolicyMap[]; + + DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyPrefKeeper); }; -ConfigurationPolicyProvider* - ConfigurationPolicyProviderKeeper::CreateManagedPlatformProvider() { - const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list = - ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(); -#if defined(OS_WIN) - return new ConfigurationPolicyProviderWin(policy_list); -#elif defined(OS_MACOSX) - return new ConfigurationPolicyProviderMac(policy_list); -#elif defined(OS_POSIX) - FilePath config_dir_path; - if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) { - return new ConfigDirPolicyProvider( - policy_list, - config_dir_path.Append(FILE_PATH_LITERAL("managed"))); - } else { - return new DummyConfigurationPolicyProvider(policy_list); - } -#else - return new DummyConfigurationPolicyProvider(policy_list); -#endif -} - -ConfigurationPolicyProvider* - ConfigurationPolicyProviderKeeper::CreateDeviceManagementProvider() { - return new DummyConfigurationPolicyProvider( - ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList()); -} - -ConfigurationPolicyProvider* - ConfigurationPolicyProviderKeeper::CreateRecommendedProvider() { - const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list = - ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(); -#if defined(OS_POSIX) && !defined(OS_MACOSX) - FilePath config_dir_path; - if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) { - return new ConfigDirPolicyProvider( - policy_list, - config_dir_path.Append(FILE_PATH_LITERAL("recommended"))); - } else { - return new DummyConfigurationPolicyProvider(policy_list); - } -#else - return new DummyConfigurationPolicyProvider(policy_list); -#endif -} - -const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry - ConfigurationPolicyPrefStore::kSimplePolicyMap[] = { +const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry + ConfigurationPolicyPrefKeeper::kSimplePolicyMap[] = { { Value::TYPE_STRING, kPolicyHomePage, prefs::kHomePage }, { Value::TYPE_BOOLEAN, kPolicyHomepageIsNewTabPage, prefs::kHomePageIsNewTabPage }, @@ -160,17 +201,21 @@ const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry { Value::TYPE_BOOLEAN, kPolicyDeveloperToolsDisabled, prefs::kDevToolsDisabled }, { Value::TYPE_BOOLEAN, kPolicyBlockThirdPartyCookies, - prefs::kBlockThirdPartyCookies}, + prefs::kBlockThirdPartyCookies }, { Value::TYPE_INTEGER, kPolicyDefaultCookiesSetting, - prefs::kManagedDefaultCookiesSetting}, + prefs::kManagedDefaultCookiesSetting }, { Value::TYPE_INTEGER, kPolicyDefaultImagesSetting, - prefs::kManagedDefaultImagesSetting}, + prefs::kManagedDefaultImagesSetting }, { Value::TYPE_INTEGER, kPolicyDefaultJavaScriptSetting, - prefs::kManagedDefaultJavaScriptSetting}, + prefs::kManagedDefaultJavaScriptSetting }, { Value::TYPE_INTEGER, kPolicyDefaultPluginsSetting, - prefs::kManagedDefaultPluginsSetting}, + prefs::kManagedDefaultPluginsSetting }, { Value::TYPE_INTEGER, kPolicyDefaultPopupsSetting, - prefs::kManagedDefaultPopupsSetting}, + prefs::kManagedDefaultPopupsSetting }, + { Value::TYPE_INTEGER, kPolicyDefaultNotificationSetting, + prefs::kDesktopNotificationDefaultContentSetting }, + { Value::TYPE_INTEGER, kPolicyDefaultGeolocationSetting, + prefs::kGeolocationDefaultContentSetting }, { Value::TYPE_STRING, kPolicyAuthSchemes, prefs::kAuthSchemes }, { Value::TYPE_BOOLEAN, kPolicyDisableAuthNegotiateCnameLookup, @@ -192,8 +237,8 @@ const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry #endif }; -const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry - ConfigurationPolicyPrefStore::kDefaultSearchPolicyMap[] = { +const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry + ConfigurationPolicyPrefKeeper::kDefaultSearchPolicyMap[] = { { Value::TYPE_BOOLEAN, kPolicyDefaultSearchProviderEnabled, prefs::kDefaultSearchProviderEnabled }, { Value::TYPE_STRING, kPolicyDefaultSearchProviderName, @@ -210,137 +255,53 @@ const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry prefs::kDefaultSearchProviderEncodings }, }; -const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry - ConfigurationPolicyPrefStore::kProxyPolicyMap[] = { +const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry + ConfigurationPolicyPrefKeeper::kProxyPolicyMap[] = { { Value::TYPE_STRING, kPolicyProxyServer, prefs::kProxyServer }, { Value::TYPE_STRING, kPolicyProxyPacUrl, prefs::kProxyPacUrl }, { Value::TYPE_STRING, kPolicyProxyBypassList, prefs::kProxyBypassList } }; -/* static */ -const ConfigurationPolicyProvider::PolicyDefinitionList* -ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList() { - static ConfigurationPolicyProvider::PolicyDefinitionList::Entry entries[] = { - { kPolicyHomePage, Value::TYPE_STRING, key::kHomepageLocation }, - { kPolicyHomepageIsNewTabPage, Value::TYPE_BOOLEAN, - key::kHomepageIsNewTabPage }, - { kPolicyRestoreOnStartup, Value::TYPE_INTEGER, key::kRestoreOnStartup }, - { kPolicyURLsToRestoreOnStartup, Value::TYPE_LIST, - key::kURLsToRestoreOnStartup }, - { kPolicyDefaultSearchProviderEnabled, Value::TYPE_BOOLEAN, - key::kDefaultSearchProviderEnabled }, - { kPolicyDefaultSearchProviderName, Value::TYPE_STRING, - key::kDefaultSearchProviderName }, - { kPolicyDefaultSearchProviderKeyword, Value::TYPE_STRING, - key::kDefaultSearchProviderKeyword }, - { kPolicyDefaultSearchProviderSearchURL, Value::TYPE_STRING, - key::kDefaultSearchProviderSearchURL }, - { kPolicyDefaultSearchProviderSuggestURL, Value::TYPE_STRING, - key::kDefaultSearchProviderSuggestURL }, - { kPolicyDefaultSearchProviderIconURL, Value::TYPE_STRING, - key::kDefaultSearchProviderIconURL }, - { kPolicyDefaultSearchProviderEncodings, Value::TYPE_STRING, - key::kDefaultSearchProviderEncodings }, - { kPolicyProxyServerMode, Value::TYPE_INTEGER, key::kProxyServerMode }, - { kPolicyProxyServer, Value::TYPE_STRING, key::kProxyServer }, - { kPolicyProxyPacUrl, Value::TYPE_STRING, key::kProxyPacUrl }, - { kPolicyProxyBypassList, Value::TYPE_STRING, key::kProxyBypassList }, - { kPolicyAlternateErrorPagesEnabled, Value::TYPE_BOOLEAN, - key::kAlternateErrorPagesEnabled }, - { kPolicySearchSuggestEnabled, Value::TYPE_BOOLEAN, - key::kSearchSuggestEnabled }, - { kPolicyDnsPrefetchingEnabled, Value::TYPE_BOOLEAN, - key::kDnsPrefetchingEnabled }, - { kPolicyDisableSpdy, Value::TYPE_BOOLEAN, key::kDisableSpdy }, - { kPolicySafeBrowsingEnabled, Value::TYPE_BOOLEAN, - key::kSafeBrowsingEnabled }, - { kPolicyMetricsReportingEnabled, Value::TYPE_BOOLEAN, - key::kMetricsReportingEnabled }, - { kPolicyPasswordManagerEnabled, Value::TYPE_BOOLEAN, - key::kPasswordManagerEnabled }, - { kPolicyPasswordManagerAllowShowPasswords, Value::TYPE_BOOLEAN, - key::kPasswordManagerAllowShowPasswords }, - { kPolicyAutoFillEnabled, Value::TYPE_BOOLEAN, key::kAutoFillEnabled }, - { kPolicyDisabledPlugins, Value::TYPE_LIST, key::kDisabledPlugins }, - { kPolicyApplicationLocale, Value::TYPE_STRING, - key::kApplicationLocaleValue }, - { kPolicySyncDisabled, Value::TYPE_BOOLEAN, key::kSyncDisabled }, - { kPolicyExtensionInstallAllowList, Value::TYPE_LIST, - key::kExtensionInstallAllowList }, - { kPolicyExtensionInstallDenyList, Value::TYPE_LIST, - key::kExtensionInstallDenyList }, - { kPolicyExtensionInstallForceList, Value::TYPE_LIST, - key::kExtensionInstallForceList }, - { kPolicyShowHomeButton, Value::TYPE_BOOLEAN, key::kShowHomeButton }, - { kPolicyPrintingEnabled, Value::TYPE_BOOLEAN, key::kPrintingEnabled }, - { kPolicyJavascriptEnabled, Value::TYPE_BOOLEAN, key::kJavascriptEnabled }, - { kPolicySavingBrowserHistoryDisabled, Value::TYPE_BOOLEAN, - key::kSavingBrowserHistoryDisabled }, - { kPolicyDeveloperToolsDisabled, Value::TYPE_BOOLEAN, - key::kDeveloperToolsDisabled }, - { kPolicyBlockThirdPartyCookies, Value::TYPE_BOOLEAN, - key::kBlockThirdPartyCookies }, - { kPolicyDefaultCookiesSetting, Value::TYPE_INTEGER, - key::kDefaultCookiesSetting}, - { kPolicyDefaultImagesSetting, Value::TYPE_INTEGER, - key::kDefaultImagesSetting}, - { kPolicyDefaultJavaScriptSetting, Value::TYPE_INTEGER, - key::kDefaultJavaScriptSetting}, - { kPolicyDefaultPluginsSetting, Value::TYPE_INTEGER, - key::kDefaultPluginsSetting}, - { kPolicyDefaultPopupsSetting, Value::TYPE_INTEGER, - key::kDefaultPopupsSetting}, - { kPolicyAuthSchemes, Value::TYPE_STRING, key::kAuthSchemes }, - { kPolicyDisableAuthNegotiateCnameLookup, Value::TYPE_BOOLEAN, - key::kDisableAuthNegotiateCnameLookup }, - { kPolicyEnableAuthNegotiatePort, Value::TYPE_BOOLEAN, - key::kEnableAuthNegotiatePort }, - { kPolicyAuthServerWhitelist, Value::TYPE_STRING, - key::kAuthServerWhitelist }, - { kPolicyAuthNegotiateDelegateWhitelist, Value::TYPE_STRING, - key::kAuthNegotiateDelegateWhitelist }, - { kPolicyGSSAPILibraryName, Value::TYPE_STRING, - key::kGSSAPILibraryName }, - { kPolicyDisable3DAPIs, Value::TYPE_BOOLEAN, - key::kDisable3DAPIs }, +ConfigurationPolicyPrefKeeper::ConfigurationPolicyPrefKeeper( + ConfigurationPolicyProvider* provider) + : lower_priority_proxy_settings_overridden_(false), + proxy_disabled_(false), + proxy_configuration_specified_(false), + use_system_proxy_(false) { + if (!provider->Provide(this)) + LOG(WARNING) << "Failed to get policy from provider."; + FinalizeProxyPolicySettings(); + FinalizeDefaultSearchPolicySettings(); +} +ConfigurationPolicyPrefKeeper::~ConfigurationPolicyPrefKeeper() { + DCHECK(proxy_policies_.empty()); +} -#if defined(OS_CHROMEOS) - { kPolicyChromeOsLockOnIdleSuspend, Value::TYPE_BOOLEAN, - key::kChromeOsLockOnIdleSuspend }, -#endif - }; +PrefStore::ReadResult +ConfigurationPolicyPrefKeeper::GetValue(const std::string& key, + Value** result) const { + Value* stored_value = NULL; + if (!prefs_.GetValue(key, &stored_value)) + return PrefStore::READ_NO_VALUE; - static ConfigurationPolicyProvider::PolicyDefinitionList policy_list = { - entries, - entries + arraysize(entries), - }; - return &policy_list; -} + // Check whether there's a default value, which indicates READ_USE_DEFAULT + // should be returned. + if (stored_value->IsType(Value::TYPE_NULL)) + return PrefStore::READ_USE_DEFAULT; -ConfigurationPolicyPrefStore::ConfigurationPolicyPrefStore( - ConfigurationPolicyProvider* provider) - : provider_(provider), - prefs_(new DictionaryValue()), - lower_priority_proxy_settings_overridden_(false), - proxy_disabled_(false), - proxy_configuration_specified_(false), - use_system_proxy_(false) { + *result = stored_value; + return PrefStore::READ_OK; } -PrefStore::PrefReadError ConfigurationPolicyPrefStore::ReadPrefs() { - proxy_disabled_ = false; - proxy_configuration_specified_ = false; - lower_priority_proxy_settings_overridden_ = false; - - const bool success = (provider_ == NULL || provider_->Provide(this)); - FinalizeDefaultSearchPolicySettings(); - return success ? PrefStore::PREF_READ_ERROR_NONE : - PrefStore::PREF_READ_ERROR_OTHER; +void ConfigurationPolicyPrefKeeper::GetDifferingPrefPaths( + const ConfigurationPolicyPrefKeeper* other, + std::vector<std::string>* differing_prefs) const { + prefs_.GetDifferingKeys(&other->prefs_, differing_prefs); } -void ConfigurationPolicyPrefStore::Apply(ConfigurationPolicyType policy, - Value* value) { +void ConfigurationPolicyPrefKeeper::Apply(ConfigurationPolicyType policy, + Value* value) { if (ApplyProxyPolicy(policy, value)) return; @@ -363,49 +324,8 @@ void ConfigurationPolicyPrefStore::Apply(ConfigurationPolicyType policy, delete value; } -// static -ConfigurationPolicyPrefStore* -ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore() { - ConfigurationPolicyProviderKeeper* keeper = - Singleton<ConfigurationPolicyProviderKeeper>::get(); - return new ConfigurationPolicyPrefStore(keeper->managed_platform_provider()); -} - -// static -ConfigurationPolicyPrefStore* -ConfigurationPolicyPrefStore::CreateDeviceManagementPolicyPrefStore( - Profile* profile) { - ConfigurationPolicyProviderKeeper* keeper = - Singleton<ConfigurationPolicyProviderKeeper>::get(); - ConfigurationPolicyProvider* provider = NULL; - if (profile) - provider = profile->GetPolicyContext()->GetDeviceManagementPolicyProvider(); - if (!provider) - provider = keeper->device_management_provider(); - return new ConfigurationPolicyPrefStore(provider); -} - -// static -ConfigurationPolicyPrefStore* -ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore() { - ConfigurationPolicyProviderKeeper* keeper = - Singleton<ConfigurationPolicyProviderKeeper>::get(); - return new ConfigurationPolicyPrefStore(keeper->recommended_provider()); -} - -// static -void ConfigurationPolicyPrefStore::GetProxyPreferenceSet( - ProxyPreferenceSet* proxy_pref_set) { - proxy_pref_set->clear(); - for (size_t current = 0; current < arraysize(kProxyPolicyMap); ++current) { - proxy_pref_set->insert(kProxyPolicyMap[current].preference_path); - } - proxy_pref_set->insert(prefs::kNoProxyServer); - proxy_pref_set->insert(prefs::kProxyAutoDetect); -} - -const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry* -ConfigurationPolicyPrefStore::FindPolicyInMap( +const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry* +ConfigurationPolicyPrefKeeper::FindPolicyInMap( ConfigurationPolicyType policy, const PolicyToPreferenceMapEntry* map, int table_size) const { @@ -416,17 +336,17 @@ ConfigurationPolicyPrefStore::FindPolicyInMap( return NULL; } -bool ConfigurationPolicyPrefStore::RemovePreferencesOfMap( +bool ConfigurationPolicyPrefKeeper::RemovePreferencesOfMap( const PolicyToPreferenceMapEntry* map, int table_size) { bool found_any = false; for (int i = 0; i < table_size; ++i) { - if (prefs_->Remove(map[i].preference_path, NULL)) + if (prefs_.RemoveValue(map[i].preference_path)) found_any = true; } return found_any; } -bool ConfigurationPolicyPrefStore::ApplyPolicyFromMap( +bool ConfigurationPolicyPrefKeeper::ApplyPolicyFromMap( ConfigurationPolicyType policy, Value* value, const PolicyToPreferenceMapEntry* map, @@ -437,124 +357,37 @@ bool ConfigurationPolicyPrefStore::ApplyPolicyFromMap( << "mismatch in provided and expected policy value for preferences" << map[current].preference_path << ". expected = " << map[current].value_type << ", actual = "<< value->GetType(); - prefs_->Set(map[current].preference_path, value); + prefs_.SetValue(map[current].preference_path, value); return true; } } return false; } -bool ConfigurationPolicyPrefStore::ApplyProxyPolicy( +bool ConfigurationPolicyPrefKeeper::ApplyProxyPolicy( ConfigurationPolicyType policy, Value* value) { - bool result = false; - bool warn_about_proxy_disable_config = false; - bool warn_about_proxy_system_config = false; - - const PolicyToPreferenceMapEntry* match_entry = - FindPolicyInMap(policy, kProxyPolicyMap, arraysize(kProxyPolicyMap)); - - // When the first proxy-related policy is applied, ALL proxy-related - // preferences that have been set by command-line switches, extensions, - // user preferences or any other mechanism are overridden. Otherwise - // it's possible for a user to interfere with proxy policy by setting - // proxy-related command-line switches or set proxy-related prefs in an - // extension that are related, but not identical, to the ones set through - // policy. - if (!lower_priority_proxy_settings_overridden_ && - (match_entry || - policy == kPolicyProxyServerMode)) { - ProxyPreferenceSet proxy_preference_set; - GetProxyPreferenceSet(&proxy_preference_set); - for (ProxyPreferenceSet::const_iterator i = proxy_preference_set.begin(); - i != proxy_preference_set.end(); ++i) { - prefs_->Set(*i, PrefStore::CreateUseDefaultSentinelValue()); - } - lower_priority_proxy_settings_overridden_ = true; - } - - // Translate the proxy policy into preferences. - if (policy == kPolicyProxyServerMode) { - int int_value; - bool proxy_auto_detect = false; - if (value->GetAsInteger(&int_value)) { - result = true; - switch (int_value) { - case kPolicyNoProxyServerMode: - if (!proxy_disabled_) { - if (proxy_configuration_specified_) - warn_about_proxy_disable_config = true; - proxy_disabled_ = true; - } - break; - case kPolicyAutoDetectProxyMode: - proxy_auto_detect = true; - break; - case kPolicyManuallyConfiguredProxyMode: - break; - case kPolicyUseSystemProxyMode: - if (!use_system_proxy_) { - if (proxy_configuration_specified_) - warn_about_proxy_system_config = true; - use_system_proxy_ = true; - } - break; - default: - // Not a valid policy, don't assume ownership of |value| - result = false; - break; - } - - if (int_value != kPolicyUseSystemProxyMode) { - prefs_->Set(prefs::kNoProxyServer, - Value::CreateBooleanValue(proxy_disabled_)); - prefs_->Set(prefs::kProxyAutoDetect, - Value::CreateBooleanValue(proxy_auto_detect)); - } - } - } else if (match_entry) { - // Determine if the applied proxy policy settings conflict and issue - // a corresponding warning if they do. - if (!proxy_configuration_specified_) { - if (proxy_disabled_) - warn_about_proxy_disable_config = true; - if (use_system_proxy_) - warn_about_proxy_system_config = true; - proxy_configuration_specified_ = true; - } - if (!use_system_proxy_ && !proxy_disabled_) { - prefs_->Set(match_entry->preference_path, value); - // The ownership of value has been passed on to |prefs_|, - // don't clean it up later. - value = NULL; - } - result = true; - } - - if (warn_about_proxy_disable_config) { - LOG(WARNING) << "A centrally-administered policy disables the use of" - << " a proxy but also specifies an explicit proxy" - << " configuration."; - } - - if (warn_about_proxy_system_config) { - LOG(WARNING) << "A centrally-administered policy dictates that the" - << " system proxy settings should be used but also specifies" - << " an explicit proxy configuration."; + // We only collect the values until we have sufficient information when + // FinalizeProxyPolicySettings() is called to determine whether the presented + // values were correct and apply them in that case. + if (policy == kPolicyProxyMode || + policy == kPolicyProxyServer || + policy == kPolicyProxyPacUrl || + policy == kPolicyProxyBypassList) { + delete proxy_policies_[policy]; + proxy_policies_[policy] = value; + return true; } - - // If the policy was a proxy policy, cleanup |value|. - if (result && value) - delete value; - return result; + // We are not interested in this policy. + return false; } -bool ConfigurationPolicyPrefStore::ApplySyncPolicy( +bool ConfigurationPolicyPrefKeeper::ApplySyncPolicy( ConfigurationPolicyType policy, Value* value) { if (policy == kPolicySyncDisabled) { bool disable_sync; if (value->GetAsBoolean(&disable_sync) && disable_sync) - prefs_->Set(prefs::kSyncManaged, value); + prefs_.SetValue(prefs::kSyncManaged, value); else delete value; return true; @@ -562,23 +395,24 @@ bool ConfigurationPolicyPrefStore::ApplySyncPolicy( return false; } -bool ConfigurationPolicyPrefStore::ApplyAutoFillPolicy( +bool ConfigurationPolicyPrefKeeper::ApplyAutoFillPolicy( ConfigurationPolicyType policy, Value* value) { if (policy == kPolicyAutoFillEnabled) { bool auto_fill_enabled; if (value->GetAsBoolean(&auto_fill_enabled) && !auto_fill_enabled) - prefs_->Set(prefs::kAutoFillEnabled, Value::CreateBooleanValue(false)); + prefs_.SetValue(prefs::kAutoFillEnabled, + Value::CreateBooleanValue(false)); delete value; return true; } return false; } -void ConfigurationPolicyPrefStore::EnsureStringPrefExists( +void ConfigurationPolicyPrefKeeper::EnsureStringPrefExists( const std::string& path) { std::string value; - if (!prefs_->GetString(path, &value)) - prefs_->SetString(path, value); + if (!prefs_.GetString(path, &value)) + prefs_.SetString(path, value); } namespace { @@ -604,24 +438,24 @@ class SearchTermsDataForValidation : public SearchTermsData { DISALLOW_COPY_AND_ASSIGN(SearchTermsDataForValidation); }; -} // namepsace +} // namespace -void ConfigurationPolicyPrefStore::FinalizeDefaultSearchPolicySettings() { +void ConfigurationPolicyPrefKeeper::FinalizeDefaultSearchPolicySettings() { bool enabled = true; - if (prefs_->GetBoolean(prefs::kDefaultSearchProviderEnabled, &enabled) && + if (prefs_.GetBoolean(prefs::kDefaultSearchProviderEnabled, &enabled) && !enabled) { // If default search is disabled, we ignore the other fields. - prefs_->SetString(prefs::kDefaultSearchProviderName, std::string()); - prefs_->SetString(prefs::kDefaultSearchProviderSearchURL, std::string()); - prefs_->SetString(prefs::kDefaultSearchProviderSuggestURL, std::string()); - prefs_->SetString(prefs::kDefaultSearchProviderIconURL, std::string()); - prefs_->SetString(prefs::kDefaultSearchProviderEncodings, std::string()); - prefs_->SetString(prefs::kDefaultSearchProviderKeyword, std::string()); + prefs_.SetString(prefs::kDefaultSearchProviderName, std::string()); + prefs_.SetString(prefs::kDefaultSearchProviderSearchURL, std::string()); + prefs_.SetString(prefs::kDefaultSearchProviderSuggestURL, std::string()); + prefs_.SetString(prefs::kDefaultSearchProviderIconURL, std::string()); + prefs_.SetString(prefs::kDefaultSearchProviderEncodings, std::string()); + prefs_.SetString(prefs::kDefaultSearchProviderKeyword, std::string()); return; } std::string search_url; // The search URL is required. - if (prefs_->GetString(prefs::kDefaultSearchProviderSearchURL, &search_url) && + if (prefs_.GetString(prefs::kDefaultSearchProviderSearchURL, &search_url) && !search_url.empty()) { SearchTermsDataForValidation search_terms_data; const TemplateURLRef search_url_ref(search_url, 0, 0); @@ -636,14 +470,14 @@ void ConfigurationPolicyPrefStore::FinalizeDefaultSearchPolicySettings() { // For the name, default to the host if not specified. std::string name; - if (!prefs_->GetString(prefs::kDefaultSearchProviderName, &name) || + if (!prefs_.GetString(prefs::kDefaultSearchProviderName, &name) || name.empty()) - prefs_->SetString(prefs::kDefaultSearchProviderName, + prefs_.SetString(prefs::kDefaultSearchProviderName, GURL(search_url).host()); // And clear the IDs since these are not specified via policy. - prefs_->SetString(prefs::kDefaultSearchProviderID, std::string()); - prefs_->SetString(prefs::kDefaultSearchProviderPrepopulateID, + prefs_.SetString(prefs::kDefaultSearchProviderID, std::string()); + prefs_.SetString(prefs::kDefaultSearchProviderPrepopulateID, std::string()); return; } @@ -653,4 +487,419 @@ void ConfigurationPolicyPrefStore::FinalizeDefaultSearchPolicySettings() { arraysize(kDefaultSearchPolicyMap)); } +void ConfigurationPolicyPrefKeeper::FinalizeProxyPolicySettings() { + if (CheckProxySettings()) + ApplyProxySettings(); + + STLDeleteContainerPairSecondPointers(proxy_policies_.begin(), + proxy_policies_.end()); + proxy_policies_.clear(); +} + +bool ConfigurationPolicyPrefKeeper::CheckProxySettings() { + bool mode = HasProxyPolicy(kPolicyProxyMode); + bool server = HasProxyPolicy(kPolicyProxyServer); + bool pac_url = HasProxyPolicy(kPolicyProxyPacUrl); + bool bypass_list = HasProxyPolicy(kPolicyProxyBypassList); + + if ((server || pac_url || bypass_list) && !mode) { + LOG(WARNING) << "A centrally-administered policy defines proxy setting" + << " details without setting a proxy mode."; + return false; + } + + if (!mode) + return true; + + int mode_value; + if (!proxy_policies_[kPolicyProxyMode]->GetAsInteger(&mode_value)) { + LOG(WARNING) << "Invalid proxy mode value."; + return false; + } + + switch (mode_value) { + case kPolicyNoProxyServerMode: + if (server || pac_url || bypass_list) { + LOG(WARNING) << "A centrally-administered policy disables the use of" + << " a proxy but also specifies an explicit proxy" + << " configuration."; + return false; + } + break; + case kPolicyAutoDetectProxyMode: + if (server || bypass_list) { + LOG(WARNING) << "A centrally-administered policy dictates that a proxy" + << " shall be auto configured but specifies fixed proxy" + << " servers or a by-pass list."; + return false; + } + break; + case kPolicyManuallyConfiguredProxyMode: + if (!server) { + LOG(WARNING) << "A centrally-administered policy dictates that the" + << " system proxy settings should use fixed proxy servers" + << " without specifying which ones."; + return false; + } + if (pac_url) { + LOG(WARNING) << "A centrally-administered policy dictates that the" + << " system proxy settings should use fixed proxy servers" + << " but also specifies a PAC script."; + return false; + } + break; + case kPolicyUseSystemProxyMode: + if (server || pac_url || bypass_list) { + LOG(WARNING) << "A centrally-administered policy dictates that the" + << " system proxy settings should be used but also " + << " specifies an explicit proxy configuration."; + return false; + } + break; + default: + LOG(WARNING) << "Invalid proxy mode " << mode_value; + return false; + } + return true; +} + +void ConfigurationPolicyPrefKeeper::ApplyProxySettings() { + if (!HasProxyPolicy(kPolicyProxyMode)) + return; + + int int_mode; + CHECK(proxy_policies_[kPolicyProxyMode]->GetAsInteger(&int_mode)); + ProxyPrefs::ProxyMode mode; + switch (int_mode) { + case kPolicyNoProxyServerMode: + mode = ProxyPrefs::MODE_DIRECT; + break; + case kPolicyAutoDetectProxyMode: + mode = ProxyPrefs::MODE_AUTO_DETECT; + if (HasProxyPolicy(kPolicyProxyPacUrl)) + mode = ProxyPrefs::MODE_PAC_SCRIPT; + break; + case kPolicyManuallyConfiguredProxyMode: + mode = ProxyPrefs::MODE_FIXED_SERVERS; + break; + case kPolicyUseSystemProxyMode: + mode = ProxyPrefs::MODE_SYSTEM; + break; + default: + mode = ProxyPrefs::MODE_DIRECT; + NOTREACHED(); + } + prefs_.SetValue(prefs::kProxyMode, Value::CreateIntegerValue(mode)); + + if (HasProxyPolicy(kPolicyProxyServer)) { + prefs_.SetValue(prefs::kProxyServer, proxy_policies_[kPolicyProxyServer]); + proxy_policies_[kPolicyProxyServer] = NULL; + } else { + prefs_.SetValue(prefs::kProxyServer, Value::CreateNullValue()); + } + if (HasProxyPolicy(kPolicyProxyPacUrl)) { + prefs_.SetValue(prefs::kProxyPacUrl, proxy_policies_[kPolicyProxyPacUrl]); + proxy_policies_[kPolicyProxyPacUrl] = NULL; + } else { + prefs_.SetValue(prefs::kProxyPacUrl, Value::CreateNullValue()); + } + if (HasProxyPolicy(kPolicyProxyBypassList)) { + prefs_.SetValue(prefs::kProxyBypassList, + proxy_policies_[kPolicyProxyBypassList]); + proxy_policies_[kPolicyProxyBypassList] = NULL; + } else { + prefs_.SetValue(prefs::kProxyBypassList, Value::CreateNullValue()); + } +} + +bool ConfigurationPolicyPrefKeeper::HasProxyPolicy( + ConfigurationPolicyType policy) const { + std::map<ConfigurationPolicyType, Value*>::const_iterator iter; + iter = proxy_policies_.find(policy); + return iter != proxy_policies_.end() && + iter->second && !iter->second->IsType(Value::TYPE_NULL); +} + +namespace { + +// Manages the lifecycle of the shared platform-specific policy providers for +// managed platform, device management and recommended policy. Instantiated as a +// Singleton. +class ConfigurationPolicyProviderKeeper { + public: + ConfigurationPolicyProviderKeeper() + : managed_platform_provider_(CreateManagedPlatformProvider()), + device_management_provider_(CreateDeviceManagementProvider()), + recommended_provider_(CreateRecommendedProvider()) {} + virtual ~ConfigurationPolicyProviderKeeper() {} + + ConfigurationPolicyProvider* managed_platform_provider() const { + return managed_platform_provider_.get(); + } + + ConfigurationPolicyProvider* device_management_provider() const { + return device_management_provider_.get(); + } + + ConfigurationPolicyProvider* recommended_provider() const { + return recommended_provider_.get(); + } + + private: + scoped_ptr<ConfigurationPolicyProvider> managed_platform_provider_; + scoped_ptr<ConfigurationPolicyProvider> device_management_provider_; + scoped_ptr<ConfigurationPolicyProvider> recommended_provider_; + + static ConfigurationPolicyProvider* CreateManagedPlatformProvider(); + static ConfigurationPolicyProvider* CreateDeviceManagementProvider(); + static ConfigurationPolicyProvider* CreateRecommendedProvider(); + + DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderKeeper); +}; + +static base::LazyInstance<ConfigurationPolicyProviderKeeper> + g_configuration_policy_provider_keeper(base::LINKER_INITIALIZED); + +ConfigurationPolicyProvider* +ConfigurationPolicyProviderKeeper::CreateManagedPlatformProvider() { + const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list = + ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(); +#if defined(OS_WIN) + return new ConfigurationPolicyProviderWin(policy_list); +#elif defined(OS_MACOSX) + return new ConfigurationPolicyProviderMac(policy_list); +#elif defined(OS_POSIX) + FilePath config_dir_path; + if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) { + return new ConfigDirPolicyProvider( + policy_list, + config_dir_path.Append(FILE_PATH_LITERAL("managed"))); + } else { + return new DummyConfigurationPolicyProvider(policy_list); + } +#else + return new DummyConfigurationPolicyProvider(policy_list); +#endif +} + +ConfigurationPolicyProvider* +ConfigurationPolicyProviderKeeper::CreateDeviceManagementProvider() { + return new DummyConfigurationPolicyProvider( + ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList()); +} + +ConfigurationPolicyProvider* +ConfigurationPolicyProviderKeeper::CreateRecommendedProvider() { + const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list = + ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(); +#if defined(OS_POSIX) && !defined(OS_MACOSX) + FilePath config_dir_path; + if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) { + return new ConfigDirPolicyProvider( + policy_list, + config_dir_path.Append(FILE_PATH_LITERAL("recommended"))); + } else { + return new DummyConfigurationPolicyProvider(policy_list); + } +#else + return new DummyConfigurationPolicyProvider(policy_list); +#endif +} + +} // namespace + +ConfigurationPolicyPrefStore::ConfigurationPolicyPrefStore( + ConfigurationPolicyProvider* provider) + : provider_(provider), + initialization_complete_(provider->IsInitializationComplete()) { + // Read initial policy. + policy_keeper_.reset(new ConfigurationPolicyPrefKeeper(provider)); + + registrar_.Init(provider_); + registrar_.AddObserver(this); +} + +ConfigurationPolicyPrefStore::~ConfigurationPolicyPrefStore() { +} + +void ConfigurationPolicyPrefStore::AddObserver(PrefStore::Observer* observer) { + observers_.AddObserver(observer); +} + +void ConfigurationPolicyPrefStore::RemoveObserver( + PrefStore::Observer* observer) { + observers_.RemoveObserver(observer); +} + +bool ConfigurationPolicyPrefStore::IsInitializationComplete() const { + return initialization_complete_; +} + +PrefStore::ReadResult +ConfigurationPolicyPrefStore::GetValue(const std::string& key, + Value** value) const { + return policy_keeper_->GetValue(key, value); +} + +void ConfigurationPolicyPrefStore::OnUpdatePolicy() { + Refresh(); +} + +// static +ConfigurationPolicyPrefStore* +ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore() { + return new ConfigurationPolicyPrefStore( + g_configuration_policy_provider_keeper.Get().managed_platform_provider()); +} + +// static +ConfigurationPolicyPrefStore* +ConfigurationPolicyPrefStore::CreateDeviceManagementPolicyPrefStore( + Profile* profile) { + ConfigurationPolicyProviderKeeper* keeper = + g_configuration_policy_provider_keeper.Pointer(); + ConfigurationPolicyProvider* provider = NULL; + if (profile) + provider = profile->GetPolicyContext()->GetDeviceManagementPolicyProvider(); + if (!provider) + provider = keeper->device_management_provider(); + return new ConfigurationPolicyPrefStore(provider); +} + +// static +ConfigurationPolicyPrefStore* +ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore() { + return new ConfigurationPolicyPrefStore( + g_configuration_policy_provider_keeper.Get().recommended_provider()); +} + +/* static */ +const ConfigurationPolicyProvider::PolicyDefinitionList* +ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList() { + static ConfigurationPolicyProvider::PolicyDefinitionList::Entry entries[] = { + { kPolicyHomePage, Value::TYPE_STRING, key::kHomepageLocation }, + { kPolicyHomepageIsNewTabPage, Value::TYPE_BOOLEAN, + key::kHomepageIsNewTabPage }, + { kPolicyRestoreOnStartup, Value::TYPE_INTEGER, key::kRestoreOnStartup }, + { kPolicyURLsToRestoreOnStartup, Value::TYPE_LIST, + key::kURLsToRestoreOnStartup }, + { kPolicyDefaultSearchProviderEnabled, Value::TYPE_BOOLEAN, + key::kDefaultSearchProviderEnabled }, + { kPolicyDefaultSearchProviderName, Value::TYPE_STRING, + key::kDefaultSearchProviderName }, + { kPolicyDefaultSearchProviderKeyword, Value::TYPE_STRING, + key::kDefaultSearchProviderKeyword }, + { kPolicyDefaultSearchProviderSearchURL, Value::TYPE_STRING, + key::kDefaultSearchProviderSearchURL }, + { kPolicyDefaultSearchProviderSuggestURL, Value::TYPE_STRING, + key::kDefaultSearchProviderSuggestURL }, + { kPolicyDefaultSearchProviderIconURL, Value::TYPE_STRING, + key::kDefaultSearchProviderIconURL }, + { kPolicyDefaultSearchProviderEncodings, Value::TYPE_STRING, + key::kDefaultSearchProviderEncodings }, + { kPolicyProxyMode, Value::TYPE_INTEGER, key::kProxyMode }, + { kPolicyProxyServer, Value::TYPE_STRING, key::kProxyServer }, + { kPolicyProxyPacUrl, Value::TYPE_STRING, key::kProxyPacUrl }, + { kPolicyProxyBypassList, Value::TYPE_STRING, key::kProxyBypassList }, + { kPolicyAlternateErrorPagesEnabled, Value::TYPE_BOOLEAN, + key::kAlternateErrorPagesEnabled }, + { kPolicySearchSuggestEnabled, Value::TYPE_BOOLEAN, + key::kSearchSuggestEnabled }, + { kPolicyDnsPrefetchingEnabled, Value::TYPE_BOOLEAN, + key::kDnsPrefetchingEnabled }, + { kPolicyDisableSpdy, Value::TYPE_BOOLEAN, key::kDisableSpdy }, + { kPolicySafeBrowsingEnabled, Value::TYPE_BOOLEAN, + key::kSafeBrowsingEnabled }, + { kPolicyMetricsReportingEnabled, Value::TYPE_BOOLEAN, + key::kMetricsReportingEnabled }, + { kPolicyPasswordManagerEnabled, Value::TYPE_BOOLEAN, + key::kPasswordManagerEnabled }, + { kPolicyPasswordManagerAllowShowPasswords, Value::TYPE_BOOLEAN, + key::kPasswordManagerAllowShowPasswords }, + { kPolicyAutoFillEnabled, Value::TYPE_BOOLEAN, key::kAutoFillEnabled }, + { kPolicyDisabledPlugins, Value::TYPE_LIST, key::kDisabledPlugins }, + { kPolicyApplicationLocale, Value::TYPE_STRING, + key::kApplicationLocaleValue }, + { kPolicySyncDisabled, Value::TYPE_BOOLEAN, key::kSyncDisabled }, + { kPolicyExtensionInstallAllowList, Value::TYPE_LIST, + key::kExtensionInstallAllowList }, + { kPolicyExtensionInstallDenyList, Value::TYPE_LIST, + key::kExtensionInstallDenyList }, + { kPolicyExtensionInstallForceList, Value::TYPE_LIST, + key::kExtensionInstallForceList }, + { kPolicyShowHomeButton, Value::TYPE_BOOLEAN, key::kShowHomeButton }, + { kPolicyPrintingEnabled, Value::TYPE_BOOLEAN, key::kPrintingEnabled }, + { kPolicyJavascriptEnabled, Value::TYPE_BOOLEAN, key::kJavascriptEnabled }, + { kPolicySavingBrowserHistoryDisabled, Value::TYPE_BOOLEAN, + key::kSavingBrowserHistoryDisabled }, + { kPolicyDeveloperToolsDisabled, Value::TYPE_BOOLEAN, + key::kDeveloperToolsDisabled }, + { kPolicyBlockThirdPartyCookies, Value::TYPE_BOOLEAN, + key::kBlockThirdPartyCookies }, + { kPolicyDefaultCookiesSetting, Value::TYPE_INTEGER, + key::kDefaultCookiesSetting }, + { kPolicyDefaultImagesSetting, Value::TYPE_INTEGER, + key::kDefaultImagesSetting }, + { kPolicyDefaultJavaScriptSetting, Value::TYPE_INTEGER, + key::kDefaultJavaScriptSetting }, + { kPolicyDefaultPluginsSetting, Value::TYPE_INTEGER, + key::kDefaultPluginsSetting }, + { kPolicyDefaultPopupsSetting, Value::TYPE_INTEGER, + key::kDefaultPopupsSetting }, + { kPolicyDefaultNotificationSetting, Value::TYPE_INTEGER, + key::kDefaultNotificationSetting }, + { kPolicyDefaultGeolocationSetting, Value::TYPE_INTEGER, + key::kDefaultGeolocationSetting }, + { kPolicyAuthSchemes, Value::TYPE_STRING, key::kAuthSchemes }, + { kPolicyDisableAuthNegotiateCnameLookup, Value::TYPE_BOOLEAN, + key::kDisableAuthNegotiateCnameLookup }, + { kPolicyEnableAuthNegotiatePort, Value::TYPE_BOOLEAN, + key::kEnableAuthNegotiatePort }, + { kPolicyAuthServerWhitelist, Value::TYPE_STRING, + key::kAuthServerWhitelist }, + { kPolicyAuthNegotiateDelegateWhitelist, Value::TYPE_STRING, + key::kAuthNegotiateDelegateWhitelist }, + { kPolicyGSSAPILibraryName, Value::TYPE_STRING, + key::kGSSAPILibraryName }, + { kPolicyDisable3DAPIs, Value::TYPE_BOOLEAN, + key::kDisable3DAPIs }, + +#if defined(OS_CHROMEOS) + { kPolicyChromeOsLockOnIdleSuspend, Value::TYPE_BOOLEAN, + key::kChromeOsLockOnIdleSuspend }, +#endif + }; + + static ConfigurationPolicyProvider::PolicyDefinitionList policy_list = { + entries, + entries + arraysize(entries), + }; + return &policy_list; +} + +void ConfigurationPolicyPrefStore::Refresh() { + // Construct a new keeper, determine what changed and swap the keeper in. + scoped_ptr<ConfigurationPolicyPrefKeeper> new_keeper( + new ConfigurationPolicyPrefKeeper(provider_)); + std::vector<std::string> changed_prefs; + new_keeper->GetDifferingPrefPaths(policy_keeper_.get(), &changed_prefs); + policy_keeper_.reset(new_keeper.release()); + + // Send out change notifications. + for (std::vector<std::string>::const_iterator pref(changed_prefs.begin()); + pref != changed_prefs.end(); + ++pref) { + FOR_EACH_OBSERVER(PrefStore::Observer, observers_, + OnPrefValueChanged(*pref)); + } + + // Update the initialization flag. + if (!initialization_complete_ && + provider_->IsInitializationComplete()) { + initialization_complete_ = true; + FOR_EACH_OBSERVER(PrefStore::Observer, observers_, + OnInitializationCompleted()); + } +} + } // namespace policy diff --git a/chrome/browser/policy/configuration_policy_pref_store.h b/chrome/browser/policy/configuration_policy_pref_store.h index be898a8..526d884 100644 --- a/chrome/browser/policy/configuration_policy_pref_store.h +++ b/chrome/browser/policy/configuration_policy_pref_store.h @@ -10,7 +10,7 @@ #include <string> #include "base/basictypes.h" -#include "base/gtest_prod_util.h" +#include "base/observer_list.h" #include "base/scoped_ptr.h" #include "base/values.h" #include "chrome/browser/policy/configuration_policy_provider.h" @@ -21,24 +21,27 @@ class Profile; namespace policy { -// An implementation of the |PrefStore| that holds a Dictionary -// created through applied policy. -class ConfigurationPolicyPrefStore : public PrefStore, - public ConfigurationPolicyStoreInterface { - public: - typedef std::set<const char*> ProxyPreferenceSet; +class ConfigurationPolicyPrefKeeper; +// An implementation of PrefStore that bridges policy settings as read from a +// ConfigurationPolicyProvider to preferences. +class ConfigurationPolicyPrefStore + : public PrefStore, + public ConfigurationPolicyProvider::Observer { + public: // The ConfigurationPolicyPrefStore does not take ownership of the // passed-in |provider|. explicit ConfigurationPolicyPrefStore(ConfigurationPolicyProvider* provider); - virtual ~ConfigurationPolicyPrefStore() {} + virtual ~ConfigurationPolicyPrefStore(); // PrefStore methods: - virtual PrefReadError ReadPrefs(); - virtual DictionaryValue* prefs() const { return prefs_.get(); } + virtual void AddObserver(PrefStore::Observer* observer); + virtual void RemoveObserver(PrefStore::Observer* observer); + virtual bool IsInitializationComplete() const; + virtual ReadResult GetValue(const std::string& key, Value** result) const; - // ConfigurationPolicyStore methods: - virtual void Apply(ConfigurationPolicyType setting, Value* value); + // ConfigurationPolicyProvider::Observer methods: + virtual void OnUpdatePolicy(); // Creates a ConfigurationPolicyPrefStore that reads managed platform policy. static ConfigurationPolicyPrefStore* CreateManagedPlatformPolicyPrefStore(); @@ -55,85 +58,27 @@ class ConfigurationPolicyPrefStore : public PrefStore, static const ConfigurationPolicyProvider::PolicyDefinitionList* GetChromePolicyDefinitionList(); - // Returns the set of preference paths that can be affected by a proxy - // policy. - static void GetProxyPreferenceSet(ProxyPreferenceSet* proxy_pref_set); - private: - // Policies that map to a single preference are handled - // by an automated converter. Each one of these policies - // has an entry in |simple_policy_map_| with the following type. - struct PolicyToPreferenceMapEntry { - Value::ValueType value_type; - ConfigurationPolicyType policy_type; - const char* preference_path; // A DictionaryValue path, not a file path. - }; - - static const PolicyToPreferenceMapEntry kSimplePolicyMap[]; - static const PolicyToPreferenceMapEntry kProxyPolicyMap[]; - static const PolicyToPreferenceMapEntry kDefaultSearchPolicyMap[]; + // Refreshes policy information, rereading policy from the provider and + // sending out change notifications as appropriate. + void Refresh(); + static const ConfigurationPolicyProvider::PolicyDefinitionList kPolicyDefinitionList; + // The policy provider from which policy settings are read. ConfigurationPolicyProvider* provider_; - scoped_ptr<DictionaryValue> prefs_; - - // Set to false until the first proxy-relevant policy is applied. At that - // time, default values are provided for all proxy-relevant prefs - // to override any values set from stores with a lower priority. - bool lower_priority_proxy_settings_overridden_; - - // The following are used to track what proxy-relevant policy has been applied - // accross calls to Apply to provide a warning if a policy specifies a - // contradictory proxy configuration. |proxy_disabled_| is set to true if and - // only if the kPolicyNoProxyServer has been applied, - // |proxy_configuration_specified_| is set to true if and only if any other - // proxy policy other than kPolicyNoProxyServer has been applied. - bool proxy_disabled_; - bool proxy_configuration_specified_; - - // Set to true if a the proxy mode policy has been set to force Chrome - // to use the system proxy. - bool use_system_proxy_; - - // Returns the map entry that corresponds to |policy| in the map. - const PolicyToPreferenceMapEntry* FindPolicyInMap( - ConfigurationPolicyType policy, - const PolicyToPreferenceMapEntry* map, - int size) const; - - // Remove the preferences found in the map from |prefs_|. Returns true if - // any such preferences were found and removed. - bool RemovePreferencesOfMap(const PolicyToPreferenceMapEntry* map, - int table_size); - - bool ApplyPolicyFromMap(ConfigurationPolicyType policy, - Value* value, - const PolicyToPreferenceMapEntry* map, - int size); - - // Processes proxy-specific policies. Returns true if the specified policy - // is a proxy-related policy. ApplyProxyPolicy assumes the ownership - // of |value| in the case that the policy is proxy-specific. - bool ApplyProxyPolicy(ConfigurationPolicyType policy, Value* value); - - // Handles sync-related policies. Returns true if the policy was handled. - // Assumes ownership of |value| in that case. - bool ApplySyncPolicy(ConfigurationPolicyType policy, Value* value); - - // Handles policies that affect AutoFill. Returns true if the policy was - // handled and assumes ownership of |value| in that case. - bool ApplyAutoFillPolicy(ConfigurationPolicyType policy, Value* value); - - // Make sure that the |path| if present in |prefs_|. If not, set it to - // a blank string. - void EnsureStringPrefExists(const std::string& path); - - // If the required entries for default search are specified and valid, - // finalizes the policy-specified configuration by initializing the - // unspecified map entries. Otherwise wipes all default search related - // map entries from |prefs_|. - void FinalizeDefaultSearchPolicySettings(); + + // Initialization status as reported by the policy provider the last time we + // queried it. + bool initialization_complete_; + + // Current policy preferences. + scoped_ptr<ConfigurationPolicyPrefKeeper> policy_keeper_; + + ObserverList<PrefStore::Observer, true> observers_; + + ConfigurationPolicyObserverRegistrar registrar_; DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyPrefStore); }; diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc index af9f8e4..1896aaa 100644 --- a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc +++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc @@ -2,13 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <gtest/gtest.h> - #include "base/file_path.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/mock_configuration_policy_provider.h" -#include "chrome/common/pref_names.h" +#include "chrome/browser/prefs/proxy_prefs.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_store_observer_mock.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::Mock; namespace policy { @@ -27,37 +33,38 @@ class TypeAndName { const char* pref_name_; }; +template<typename TESTBASE> +class ConfigurationPolicyPrefStoreTestBase : public TESTBASE { + protected: + ConfigurationPolicyPrefStoreTestBase() + : provider_(), + store_(&provider_) {} + + MockConfigurationPolicyProvider provider_; + ConfigurationPolicyPrefStore store_; +}; + // Test cases for list-valued policy settings. class ConfigurationPolicyPrefStoreListTest - : public testing::TestWithParam<TypeAndName> { + : public ConfigurationPolicyPrefStoreTestBase< + testing::TestWithParam<TypeAndName> > { }; TEST_P(ConfigurationPolicyPrefStoreListTest, GetDefault) { - ConfigurationPolicyPrefStore store(NULL); - ListValue* list = NULL; - EXPECT_FALSE(store.prefs()->GetList(GetParam().pref_name(), &list)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store_.GetValue(GetParam().pref_name(), NULL)); } TEST_P(ConfigurationPolicyPrefStoreListTest, SetValue) { - ConfigurationPolicyPrefStore store(NULL); ListValue* in_value = new ListValue(); in_value->Append(Value::CreateStringValue("test1")); in_value->Append(Value::CreateStringValue("test2,")); - store.Apply(GetParam().type(), in_value); - ListValue* list = NULL; - EXPECT_TRUE(store.prefs()->GetList(GetParam().pref_name(), &list)); - ListValue::const_iterator current(list->begin()); - const ListValue::const_iterator end(list->end()); - ASSERT_TRUE(current != end); - std::string value; - (*current)->GetAsString(&value); - EXPECT_EQ("test1", value); - ++current; - ASSERT_TRUE(current != end); - (*current)->GetAsString(&value); - EXPECT_EQ("test2,", value); - ++current; - EXPECT_TRUE(current == end); + provider_.AddPolicy(GetParam().type(), in_value); + store_.OnUpdatePolicy(); + Value* value; + EXPECT_EQ(PrefStore::READ_OK, + store_.GetValue(GetParam().pref_name(), &value)); + EXPECT_TRUE(in_value->Equals(value)); } INSTANTIATE_TEST_CASE_P( @@ -75,22 +82,23 @@ INSTANTIATE_TEST_CASE_P( // Test cases for string-valued policy settings. class ConfigurationPolicyPrefStoreStringTest - : public testing::TestWithParam<TypeAndName> { + : public ConfigurationPolicyPrefStoreTestBase< + testing::TestWithParam<TypeAndName> > { }; TEST_P(ConfigurationPolicyPrefStoreStringTest, GetDefault) { - ConfigurationPolicyPrefStore store(NULL); - std::string result; - EXPECT_FALSE(store.prefs()->GetString(GetParam().pref_name(), &result)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store_.GetValue(GetParam().pref_name(), NULL)); } TEST_P(ConfigurationPolicyPrefStoreStringTest, SetValue) { - ConfigurationPolicyPrefStore store(NULL); - store.Apply(GetParam().type(), - Value::CreateStringValue("http://chromium.org")); - std::string result; - EXPECT_TRUE(store.prefs()->GetString(GetParam().pref_name(), &result)); - EXPECT_EQ(result, "http://chromium.org"); + provider_.AddPolicy(GetParam().type(), + Value::CreateStringValue("http://chromium.org")); + store_.OnUpdatePolicy(); + Value* value; + EXPECT_EQ(PrefStore::READ_OK, + store_.GetValue(GetParam().pref_name(), &value)); + EXPECT_TRUE(StringValue("http://chromium.org").Equals(value)); } INSTANTIATE_TEST_CASE_P( @@ -99,12 +107,6 @@ INSTANTIATE_TEST_CASE_P( testing::Values( TypeAndName(kPolicyHomePage, prefs::kHomePage), - TypeAndName(kPolicyProxyServer, - prefs::kProxyServer), - TypeAndName(kPolicyProxyPacUrl, - prefs::kProxyPacUrl), - TypeAndName(kPolicyProxyBypassList, - prefs::kProxyBypassList), TypeAndName(kPolicyApplicationLocale, prefs::kApplicationLocale), TypeAndName(kPolicyApplicationLocale, @@ -120,26 +122,30 @@ INSTANTIATE_TEST_CASE_P( // Test cases for boolean-valued policy settings. class ConfigurationPolicyPrefStoreBooleanTest - : public testing::TestWithParam<TypeAndName> { + : public ConfigurationPolicyPrefStoreTestBase< + testing::TestWithParam<TypeAndName> > { }; TEST_P(ConfigurationPolicyPrefStoreBooleanTest, GetDefault) { - ConfigurationPolicyPrefStore store(NULL); - bool result = false; - EXPECT_FALSE(store.prefs()->GetBoolean(GetParam().pref_name(), &result)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store_.GetValue(GetParam().pref_name(), NULL)); } TEST_P(ConfigurationPolicyPrefStoreBooleanTest, SetValue) { - ConfigurationPolicyPrefStore store(NULL); - store.Apply(GetParam().type(), Value::CreateBooleanValue(false)); + provider_.AddPolicy(GetParam().type(), Value::CreateBooleanValue(false)); + store_.OnUpdatePolicy(); + Value* value; bool result = true; - EXPECT_TRUE(store.prefs()->GetBoolean(GetParam().pref_name(), &result)); - EXPECT_FALSE(result); + EXPECT_EQ(PrefStore::READ_OK, + store_.GetValue(GetParam().pref_name(), &value)); + EXPECT_TRUE(FundamentalValue(false).Equals(value)); - store.Apply(GetParam().type(), Value::CreateBooleanValue(true)); + provider_.AddPolicy(GetParam().type(), Value::CreateBooleanValue(true)); + store_.OnUpdatePolicy(); result = false; - EXPECT_TRUE(store.prefs()->GetBoolean(GetParam().pref_name(), &result)); - EXPECT_TRUE(result); + EXPECT_EQ(PrefStore::READ_OK, + store_.GetValue(GetParam().pref_name(), &value)); + EXPECT_TRUE(FundamentalValue(true).Equals(value)); } INSTANTIATE_TEST_CASE_P( @@ -192,21 +198,22 @@ INSTANTIATE_TEST_CASE_P( // Test cases for integer-valued policy settings. class ConfigurationPolicyPrefStoreIntegerTest - : public testing::TestWithParam<TypeAndName> { + : public ConfigurationPolicyPrefStoreTestBase< + testing::TestWithParam<TypeAndName> > { }; TEST_P(ConfigurationPolicyPrefStoreIntegerTest, GetDefault) { - ConfigurationPolicyPrefStore store(NULL); - int result = 0; - EXPECT_FALSE(store.prefs()->GetInteger(GetParam().pref_name(), &result)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store_.GetValue(GetParam().pref_name(), NULL)); } TEST_P(ConfigurationPolicyPrefStoreIntegerTest, SetValue) { - ConfigurationPolicyPrefStore store(NULL); - store.Apply(GetParam().type(), Value::CreateIntegerValue(2)); - int result = 0; - EXPECT_TRUE(store.prefs()->GetInteger(GetParam().pref_name(), &result)); - EXPECT_EQ(result, 2); + provider_.AddPolicy(GetParam().type(), Value::CreateIntegerValue(2)); + store_.OnUpdatePolicy(); + Value* value = NULL; + EXPECT_EQ(PrefStore::READ_OK, + store_.GetValue(GetParam().pref_name(), &value)); + EXPECT_TRUE(FundamentalValue(2).Equals(value)); } INSTANTIATE_TEST_CASE_P( @@ -218,153 +225,133 @@ INSTANTIATE_TEST_CASE_P( // Test cases for the proxy policy settings. class ConfigurationPolicyPrefStoreProxyTest : public testing::Test { + protected: + // Verify that all the proxy prefs are set to the specified expected values. + static void VerifyProxyPrefs( + const ConfigurationPolicyPrefStore& store, + const std::string& expected_proxy_server, + const std::string& expected_proxy_pac_url, + const std::string& expected_proxy_bypass_list, + const ProxyPrefs::ProxyMode& expected_proxy_mode) { + Value* value = NULL; + + if (expected_proxy_server.empty()) { + EXPECT_EQ(PrefStore::READ_USE_DEFAULT, + store.GetValue(prefs::kProxyServer, NULL)); + } else { + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kProxyServer, &value)); + EXPECT_TRUE(StringValue(expected_proxy_server).Equals(value)); + } + if (expected_proxy_pac_url.empty()) { + EXPECT_EQ(PrefStore::READ_USE_DEFAULT, + store.GetValue(prefs::kProxyPacUrl, NULL)); + } else { + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kProxyPacUrl, &value)); + EXPECT_TRUE(StringValue(expected_proxy_pac_url).Equals(value)); + } + if (expected_proxy_bypass_list.empty()) { + EXPECT_EQ(PrefStore::READ_USE_DEFAULT, + store.GetValue(prefs::kProxyBypassList, NULL)); + } else { + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kProxyBypassList, &value)); + EXPECT_TRUE(StringValue(expected_proxy_bypass_list).Equals(value)); + } + EXPECT_EQ(PrefStore::READ_OK, store.GetValue(prefs::kProxyMode, &value)); + EXPECT_TRUE(FundamentalValue(expected_proxy_mode).Equals(value)); + } }; TEST_F(ConfigurationPolicyPrefStoreProxyTest, ManualOptions) { - scoped_ptr<MockConfigurationPolicyProvider> provider( - new MockConfigurationPolicyProvider()); - provider->AddPolicy(kPolicyProxyBypassList, - Value::CreateStringValue("http://chromium.org/override")); - provider->AddPolicy(kPolicyProxyPacUrl, - Value::CreateStringValue("http://short.org/proxy.pac")); - provider->AddPolicy(kPolicyProxyServer, - Value::CreateStringValue("chromium.org")); - provider->AddPolicy(kPolicyProxyServerMode, - Value::CreateIntegerValue( - kPolicyManuallyConfiguredProxyMode)); - - ConfigurationPolicyPrefStore store(provider.get()); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - - std::string string_result; - EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyBypassList, - &string_result)); - EXPECT_EQ("http://chromium.org/override", string_result); - EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); - EXPECT_EQ("http://short.org/proxy.pac", string_result); - EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); - EXPECT_EQ("chromium.org", string_result); - bool bool_result; - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); - EXPECT_FALSE(bool_result); - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, &bool_result)); - EXPECT_FALSE(bool_result); + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyProxyBypassList, + Value::CreateStringValue("http://chromium.org/override")); + provider.AddPolicy(kPolicyProxyServer, + Value::CreateStringValue("chromium.org")); + provider.AddPolicy(kPolicyProxyMode, + Value::CreateIntegerValue( + kPolicyManuallyConfiguredProxyMode)); + + ConfigurationPolicyPrefStore store(&provider); + VerifyProxyPrefs( + store, "chromium.org", "", "http://chromium.org/override", + ProxyPrefs::MODE_FIXED_SERVERS); } -TEST_F(ConfigurationPolicyPrefStoreProxyTest, NoProxy) { - scoped_ptr<MockConfigurationPolicyProvider> provider( - new MockConfigurationPolicyProvider()); - provider->AddPolicy(kPolicyProxyBypassList, - Value::CreateStringValue("http://chromium.org/override")); - provider->AddPolicy(kPolicyProxyServerMode, - Value::CreateIntegerValue( - kPolicyNoProxyServerMode)); - - ConfigurationPolicyPrefStore store(provider.get()); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - - std::string string_result; - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList, - &string_result)); - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); - bool bool_result; - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); - EXPECT_TRUE(bool_result); - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, &bool_result)); - EXPECT_FALSE(bool_result); +TEST_F(ConfigurationPolicyPrefStoreProxyTest, ManualOptionsReversedApplyOrder) { + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyProxyMode, + Value::CreateIntegerValue( + kPolicyManuallyConfiguredProxyMode)); + provider.AddPolicy(kPolicyProxyBypassList, + Value::CreateStringValue("http://chromium.org/override")); + provider.AddPolicy(kPolicyProxyServer, + Value::CreateStringValue("chromium.org")); + + ConfigurationPolicyPrefStore store(&provider); + VerifyProxyPrefs( + store, "chromium.org", "", "http://chromium.org/override", + ProxyPrefs::MODE_FIXED_SERVERS); } -TEST_F(ConfigurationPolicyPrefStoreProxyTest, NoProxyReversedApplyOrder) { - scoped_ptr<MockConfigurationPolicyProvider> provider( - new MockConfigurationPolicyProvider()); - provider->AddPolicy(kPolicyProxyServerMode, - Value::CreateIntegerValue( - kPolicyNoProxyServerMode)); - provider->AddPolicy(kPolicyProxyBypassList, - Value::CreateStringValue("http://chromium.org/override")); - - ConfigurationPolicyPrefStore store(provider.get()); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - - std::string string_result; - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList, - &string_result)); - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); - bool bool_result; - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); - EXPECT_TRUE(bool_result); - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, &bool_result)); - EXPECT_FALSE(bool_result); +TEST_F(ConfigurationPolicyPrefStoreProxyTest, NoProxy) { + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyProxyMode, + Value::CreateIntegerValue(kPolicyNoProxyServerMode)); + + ConfigurationPolicyPrefStore store(&provider); + VerifyProxyPrefs(store, "", "", "", ProxyPrefs::MODE_DIRECT); } TEST_F(ConfigurationPolicyPrefStoreProxyTest, AutoDetect) { - scoped_ptr<MockConfigurationPolicyProvider> provider( - new MockConfigurationPolicyProvider()); - provider->AddPolicy(kPolicyProxyServerMode, - Value::CreateIntegerValue( - kPolicyAutoDetectProxyMode)); - - ConfigurationPolicyPrefStore store(provider.get()); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - - std::string string_result; - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList, - &string_result)); - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); - bool bool_result; - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); - EXPECT_FALSE(bool_result); - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, &bool_result)); - EXPECT_TRUE(bool_result); + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyProxyMode, + Value::CreateIntegerValue(kPolicyAutoDetectProxyMode)); + + ConfigurationPolicyPrefStore store(&provider); + VerifyProxyPrefs(store, "", "", "", ProxyPrefs::MODE_AUTO_DETECT); +} + +TEST_F(ConfigurationPolicyPrefStoreProxyTest, AutoDetectPac) { + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyProxyPacUrl, + Value::CreateStringValue("http://short.org/proxy.pac")); + provider.AddPolicy(kPolicyProxyMode, + Value::CreateIntegerValue(kPolicyAutoDetectProxyMode)); + + ConfigurationPolicyPrefStore store(&provider); + VerifyProxyPrefs( + store, "", "http://short.org/proxy.pac", "", ProxyPrefs::MODE_PAC_SCRIPT); } TEST_F(ConfigurationPolicyPrefStoreProxyTest, UseSystem) { - scoped_ptr<MockConfigurationPolicyProvider> provider( - new MockConfigurationPolicyProvider()); - provider->AddPolicy(kPolicyProxyBypassList, - Value::CreateStringValue("http://chromium.org/override")); - provider->AddPolicy(kPolicyProxyServerMode, - Value::CreateIntegerValue( - kPolicyUseSystemProxyMode)); - - ConfigurationPolicyPrefStore store(provider.get()); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - - std::string string_result; - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList, - &string_result)); - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); - bool bool_result; - EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); - EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, - &bool_result)); + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyProxyMode, + Value::CreateIntegerValue(kPolicyUseSystemProxyMode)); + + ConfigurationPolicyPrefStore store(&provider); + VerifyProxyPrefs(store, "", "", "", ProxyPrefs::MODE_SYSTEM); } -TEST_F(ConfigurationPolicyPrefStoreProxyTest, UseSystemReversedApplyOrder) { - scoped_ptr<MockConfigurationPolicyProvider> provider( - new MockConfigurationPolicyProvider()); - provider->AddPolicy(kPolicyProxyServerMode, - Value::CreateIntegerValue( - kPolicyUseSystemProxyMode)); - provider->AddPolicy(kPolicyProxyBypassList, - Value::CreateStringValue("http://chromium.org/override")); - - ConfigurationPolicyPrefStore store(provider.get()); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - - std::string string_result; - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList, - &string_result)); - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result)); - EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result)); - bool bool_result; - EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result)); - EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, - &bool_result)); +TEST_F(ConfigurationPolicyPrefStoreProxyTest, ProxyInvalid) { + for (int i = 0; i < MODE_COUNT; ++i) { + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyProxyMode, Value::CreateIntegerValue(i)); + // No mode expects all three parameters being set. + provider.AddPolicy(kPolicyProxyPacUrl, + Value::CreateStringValue("http://short.org/proxy.pac")); + provider.AddPolicy(kPolicyProxyBypassList, + Value::CreateStringValue( + "http://chromium.org/override")); + provider.AddPolicy(kPolicyProxyServer, + Value::CreateStringValue("chromium.org")); + + ConfigurationPolicyPrefStore store(&provider); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kProxyMode, NULL)); + } } class ConfigurationPolicyPrefStoreDefaultSearchTest : public testing::Test { @@ -374,44 +361,38 @@ class ConfigurationPolicyPrefStoreDefaultSearchTest : public testing::Test { // search URL, that all the elements have been given proper defaults. TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, MinimallyDefined) { const char* const search_url = "http://test.com/search?t={searchTerms}"; - scoped_ptr<MockConfigurationPolicyProvider> provider( - new MockConfigurationPolicyProvider()); - provider->AddPolicy( - kPolicyDefaultSearchProviderEnabled, - Value::CreateBooleanValue(true)); - provider->AddPolicy( - kPolicyDefaultSearchProviderSearchURL, - Value::CreateStringValue(search_url)); - - ConfigurationPolicyPrefStore store(provider.get()); - - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - const DictionaryValue* prefs = store.prefs(); - - std::string string_result; - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderSearchURL, - &string_result)); - EXPECT_EQ(string_result, search_url); - - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderName, - &string_result)); - EXPECT_EQ(string_result, "test.com"); - - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderKeyword, - &string_result)); - EXPECT_EQ(string_result, std::string()); - - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderSuggestURL, - &string_result)); - EXPECT_EQ(string_result, std::string()); - - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderIconURL, - &string_result)); - EXPECT_EQ(string_result, std::string()); - - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderEncodings, - &string_result)); - EXPECT_EQ(string_result, std::string()); + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyDefaultSearchProviderEnabled, + Value::CreateBooleanValue(true)); + provider.AddPolicy(kPolicyDefaultSearchProviderSearchURL, + Value::CreateStringValue(search_url)); + + ConfigurationPolicyPrefStore store(&provider); + + Value* value = NULL; + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderSearchURL, &value)); + EXPECT_TRUE(StringValue(search_url).Equals(value)); + + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderName, &value)); + EXPECT_TRUE(StringValue("test.com").Equals(value)); + + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderKeyword, &value)); + EXPECT_TRUE(StringValue(std::string()).Equals(value)); + + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderSuggestURL, &value)); + EXPECT_TRUE(StringValue(std::string()).Equals(value)); + + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderIconURL, &value)); + EXPECT_TRUE(StringValue(std::string()).Equals(value)); + + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderEncodings, &value)); + EXPECT_TRUE(StringValue(std::string()).Equals(value)); } // Checks that for a fully defined search policy, all elements have been @@ -423,63 +404,48 @@ TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, FullyDefined) { const char* const name = "MyName"; const char* const keyword = "MyKeyword"; const char* const encodings = "UTF-16;UTF-8"; - scoped_ptr<MockConfigurationPolicyProvider> provider( - new MockConfigurationPolicyProvider()); - provider->AddPolicy( - kPolicyDefaultSearchProviderEnabled, - Value::CreateBooleanValue(true)); - provider->AddPolicy( - kPolicyDefaultSearchProviderSearchURL, - Value::CreateStringValue(search_url)); - provider->AddPolicy( - kPolicyDefaultSearchProviderName, - Value::CreateStringValue(name)); - provider->AddPolicy( - kPolicyDefaultSearchProviderKeyword, - Value::CreateStringValue(keyword)); - provider->AddPolicy( - kPolicyDefaultSearchProviderSuggestURL, - Value::CreateStringValue(suggest_url)); - provider->AddPolicy( - kPolicyDefaultSearchProviderIconURL, - Value::CreateStringValue(icon_url)); - provider->AddPolicy( - kPolicyDefaultSearchProviderEncodings, - Value::CreateStringValue(encodings)); - - ConfigurationPolicyPrefStore store(provider.get()); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - const DictionaryValue* prefs = store.prefs(); - - std::string result_search_url; - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderSearchURL, - &result_search_url)); - EXPECT_EQ(result_search_url, search_url); - - std::string result_name; - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderName, - &result_name)); - EXPECT_EQ(result_name, name); - - std::string result_keyword; - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderKeyword, - &result_keyword)); - EXPECT_EQ(result_keyword, keyword); - - std::string result_suggest_url; - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderSuggestURL, - &result_suggest_url)); - EXPECT_EQ(result_suggest_url, suggest_url); - - std::string result_icon_url; - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderIconURL, - &result_icon_url)); - EXPECT_EQ(result_icon_url, icon_url); - - std::string result_encodings; - EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderEncodings, - &result_encodings)); - EXPECT_EQ(result_encodings, encodings); + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyDefaultSearchProviderEnabled, + Value::CreateBooleanValue(true)); + provider.AddPolicy(kPolicyDefaultSearchProviderSearchURL, + Value::CreateStringValue(search_url)); + provider.AddPolicy(kPolicyDefaultSearchProviderName, + Value::CreateStringValue(name)); + provider.AddPolicy(kPolicyDefaultSearchProviderKeyword, + Value::CreateStringValue(keyword)); + provider.AddPolicy(kPolicyDefaultSearchProviderSuggestURL, + Value::CreateStringValue(suggest_url)); + provider.AddPolicy(kPolicyDefaultSearchProviderIconURL, + Value::CreateStringValue(icon_url)); + provider.AddPolicy(kPolicyDefaultSearchProviderEncodings, + Value::CreateStringValue(encodings)); + + ConfigurationPolicyPrefStore store(&provider); + + Value* value = NULL; + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderSearchURL, &value)); + EXPECT_TRUE(StringValue(search_url).Equals(value)); + + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderName, &value)); + EXPECT_TRUE(StringValue(name).Equals(value)); + + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderKeyword, &value)); + EXPECT_TRUE(StringValue(keyword).Equals(value)); + + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderSuggestURL, &value)); + EXPECT_TRUE(StringValue(suggest_url).Equals(value)); + + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderIconURL, &value)); + EXPECT_TRUE(StringValue(icon_url).Equals(value)); + + EXPECT_EQ(PrefStore::READ_OK, + store.GetValue(prefs::kDefaultSearchProviderEncodings, &value)); + EXPECT_TRUE(StringValue(encodings).Equals(value)); } // Checks that if the default search policy is missing, that no elements of the @@ -490,44 +456,34 @@ TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, MissingUrl) { const char* const name = "MyName"; const char* const keyword = "MyKeyword"; const char* const encodings = "UTF-16;UTF-8"; - scoped_ptr<MockConfigurationPolicyProvider> provider( - new MockConfigurationPolicyProvider()); - provider->AddPolicy( - kPolicyDefaultSearchProviderEnabled, - Value::CreateBooleanValue(true)); - provider->AddPolicy( - kPolicyDefaultSearchProviderName, - Value::CreateStringValue(name)); - provider->AddPolicy( - kPolicyDefaultSearchProviderKeyword, - Value::CreateStringValue(keyword)); - provider->AddPolicy( - kPolicyDefaultSearchProviderSuggestURL, - Value::CreateStringValue(suggest_url)); - provider->AddPolicy( - kPolicyDefaultSearchProviderIconURL, - Value::CreateStringValue(icon_url)); - provider->AddPolicy( - kPolicyDefaultSearchProviderEncodings, - Value::CreateStringValue(encodings)); - - ConfigurationPolicyPrefStore store(provider.get()); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - const DictionaryValue* prefs = store.prefs(); - - std::string string_result; - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderSearchURL, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderName, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderKeyword, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderSuggestURL, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderIconURL, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderEncodings, - &string_result)); + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyDefaultSearchProviderEnabled, + Value::CreateBooleanValue(true)); + provider.AddPolicy(kPolicyDefaultSearchProviderName, + Value::CreateStringValue(name)); + provider.AddPolicy(kPolicyDefaultSearchProviderKeyword, + Value::CreateStringValue(keyword)); + provider.AddPolicy(kPolicyDefaultSearchProviderSuggestURL, + Value::CreateStringValue(suggest_url)); + provider.AddPolicy(kPolicyDefaultSearchProviderIconURL, + Value::CreateStringValue(icon_url)); + provider.AddPolicy(kPolicyDefaultSearchProviderEncodings, + Value::CreateStringValue(encodings)); + + ConfigurationPolicyPrefStore store(&provider); + + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderSearchURL, NULL)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderName, NULL)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderKeyword, NULL)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderSuggestURL, NULL)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderIconURL, NULL)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderEncodings, NULL)); } // Checks that if the default search policy is invalid, that no elements of the @@ -539,103 +495,146 @@ TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, Invalid) { const char* const name = "MyName"; const char* const keyword = "MyKeyword"; const char* const encodings = "UTF-16;UTF-8"; - scoped_ptr<MockConfigurationPolicyProvider> provider( - new MockConfigurationPolicyProvider()); - provider->AddPolicy( - kPolicyDefaultSearchProviderEnabled, - Value::CreateBooleanValue(true)); - provider->AddPolicy( - kPolicyDefaultSearchProviderSearchURL, - Value::CreateStringValue(bad_search_url)); - provider->AddPolicy( - kPolicyDefaultSearchProviderName, - Value::CreateStringValue(name)); - provider->AddPolicy( - kPolicyDefaultSearchProviderKeyword, - Value::CreateStringValue(keyword)); - provider->AddPolicy( - kPolicyDefaultSearchProviderSuggestURL, - Value::CreateStringValue(suggest_url)); - provider->AddPolicy( - kPolicyDefaultSearchProviderIconURL, - Value::CreateStringValue(icon_url)); - provider->AddPolicy( - kPolicyDefaultSearchProviderEncodings, - Value::CreateStringValue(encodings)); - - ConfigurationPolicyPrefStore store(provider.get()); - EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE); - const DictionaryValue* const prefs = store.prefs(); - - std::string string_result; - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderEnabled, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderSearchURL, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderName, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderKeyword, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderSuggestURL, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderIconURL, - &string_result)); - EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderEncodings, - &string_result)); + MockConfigurationPolicyProvider provider; + provider.AddPolicy(kPolicyDefaultSearchProviderEnabled, + Value::CreateBooleanValue(true)); + provider.AddPolicy(kPolicyDefaultSearchProviderSearchURL, + Value::CreateStringValue(bad_search_url)); + provider.AddPolicy(kPolicyDefaultSearchProviderName, + Value::CreateStringValue(name)); + provider.AddPolicy(kPolicyDefaultSearchProviderKeyword, + Value::CreateStringValue(keyword)); + provider.AddPolicy(kPolicyDefaultSearchProviderSuggestURL, + Value::CreateStringValue(suggest_url)); + provider.AddPolicy(kPolicyDefaultSearchProviderIconURL, + Value::CreateStringValue(icon_url)); + provider.AddPolicy(kPolicyDefaultSearchProviderEncodings, + Value::CreateStringValue(encodings)); + + ConfigurationPolicyPrefStore store(&provider); + + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderSearchURL, NULL)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderName, NULL)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderKeyword, NULL)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderSuggestURL, NULL)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderIconURL, NULL)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store.GetValue(prefs::kDefaultSearchProviderEncodings, NULL)); } // Test cases for the Sync policy setting. -class ConfigurationPolicyPrefStoreSyncTest : public testing::Test { +class ConfigurationPolicyPrefStoreSyncTest + : public ConfigurationPolicyPrefStoreTestBase<testing::Test> { }; TEST_F(ConfigurationPolicyPrefStoreSyncTest, Default) { - ConfigurationPolicyPrefStore store(NULL); - bool result = false; - EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kSyncManaged, &result)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store_.GetValue(prefs::kSyncManaged, NULL)); } TEST_F(ConfigurationPolicyPrefStoreSyncTest, Enabled) { - ConfigurationPolicyPrefStore store(NULL); - store.Apply(kPolicySyncDisabled, Value::CreateBooleanValue(false)); + provider_.AddPolicy(kPolicySyncDisabled, Value::CreateBooleanValue(false)); + store_.OnUpdatePolicy(); // Enabling Sync should not set the pref. - bool result = false; - EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kSyncManaged, &result)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store_.GetValue(prefs::kSyncManaged, NULL)); } TEST_F(ConfigurationPolicyPrefStoreSyncTest, Disabled) { - ConfigurationPolicyPrefStore store(NULL); - store.Apply(kPolicySyncDisabled, Value::CreateBooleanValue(true)); + provider_.AddPolicy(kPolicySyncDisabled, Value::CreateBooleanValue(true)); + store_.OnUpdatePolicy(); // Sync should be flagged as managed. - bool result = false; - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kSyncManaged, &result)); - EXPECT_TRUE(result); + Value* value = NULL; + EXPECT_EQ(PrefStore::READ_OK, store_.GetValue(prefs::kSyncManaged, &value)); + ASSERT_TRUE(value != NULL); + EXPECT_TRUE(FundamentalValue(true).Equals(value)); } // Test cases for the AutoFill policy setting. -class ConfigurationPolicyPrefStoreAutoFillTest : public testing::Test { +class ConfigurationPolicyPrefStoreAutoFillTest + : public ConfigurationPolicyPrefStoreTestBase<testing::Test> { }; TEST_F(ConfigurationPolicyPrefStoreAutoFillTest, Default) { - ConfigurationPolicyPrefStore store(NULL); - bool result = false; - EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kAutoFillEnabled, &result)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store_.GetValue(prefs::kSyncManaged, NULL)); } TEST_F(ConfigurationPolicyPrefStoreAutoFillTest, Enabled) { - ConfigurationPolicyPrefStore store(NULL); - store.Apply(kPolicyAutoFillEnabled, Value::CreateBooleanValue(true)); + provider_.AddPolicy(kPolicyAutoFillEnabled, Value::CreateBooleanValue(true)); + store_.OnUpdatePolicy(); // Enabling AutoFill should not set the pref. - bool result = false; - EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kAutoFillEnabled, &result)); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store_.GetValue(prefs::kSyncManaged, NULL)); } TEST_F(ConfigurationPolicyPrefStoreAutoFillTest, Disabled) { - ConfigurationPolicyPrefStore store(NULL); - store.Apply(kPolicyAutoFillEnabled, Value::CreateBooleanValue(false)); + provider_.AddPolicy(kPolicyAutoFillEnabled, Value::CreateBooleanValue(false)); + store_.OnUpdatePolicy(); // Disabling AutoFill should switch the pref to managed. - bool result = true; - EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kAutoFillEnabled, &result)); - EXPECT_FALSE(result); + Value* value = NULL; + EXPECT_EQ(PrefStore::READ_OK, + store_.GetValue(prefs::kAutoFillEnabled, &value)); + EXPECT_TRUE(FundamentalValue(false).Equals(value)); +} + +// Exercises the policy refresh mechanism. +class ConfigurationPolicyPrefStoreRefreshTest + : public ConfigurationPolicyPrefStoreTestBase<testing::Test> { + protected: + virtual void SetUp() { + store_.AddObserver(&observer_); + } + + virtual void TearDown() { + store_.RemoveObserver(&observer_); + } + + PrefStoreObserverMock observer_; +}; + +TEST_F(ConfigurationPolicyPrefStoreRefreshTest, Refresh) { + Value* value = NULL; + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store_.GetValue(prefs::kHomePage, NULL)); + + EXPECT_CALL(observer_, OnPrefValueChanged(prefs::kHomePage)).Times(1); + provider_.AddPolicy(kPolicyHomePage, + Value::CreateStringValue("http://www.chromium.org")); + store_.OnUpdatePolicy(); + Mock::VerifyAndClearExpectations(&observer_); + EXPECT_EQ(PrefStore::READ_OK, + store_.GetValue(prefs::kHomePage, &value)); + EXPECT_TRUE(StringValue("http://www.chromium.org").Equals(value)); + + EXPECT_CALL(observer_, OnPrefValueChanged(_)).Times(0); + store_.OnUpdatePolicy(); + Mock::VerifyAndClearExpectations(&observer_); + + EXPECT_CALL(observer_, OnPrefValueChanged(prefs::kHomePage)).Times(1); + provider_.RemovePolicy(kPolicyHomePage); + store_.OnUpdatePolicy(); + Mock::VerifyAndClearExpectations(&observer_); + EXPECT_EQ(PrefStore::READ_NO_VALUE, + store_.GetValue(prefs::kHomePage, NULL)); +} + +TEST_F(ConfigurationPolicyPrefStoreRefreshTest, Initialization) { + EXPECT_FALSE(store_.IsInitializationComplete()); + + EXPECT_CALL(observer_, OnInitializationCompleted()).Times(1); + + provider_.SetInitializationComplete(true); + EXPECT_FALSE(store_.IsInitializationComplete()); + + store_.OnUpdatePolicy(); + Mock::VerifyAndClearExpectations(&observer_); + EXPECT_TRUE(store_.IsInitializationComplete()); } } // namespace policy diff --git a/chrome/browser/policy/configuration_policy_provider.cc b/chrome/browser/policy/configuration_policy_provider.cc index ce7106f..2aee046 100644 --- a/chrome/browser/policy/configuration_policy_provider.cc +++ b/chrome/browser/policy/configuration_policy_provider.cc @@ -4,11 +4,45 @@ #include "chrome/browser/policy/configuration_policy_provider.h" +#include <algorithm> + #include "base/values.h" -#include "chrome/common/notification_service.h" namespace policy { +ConfigurationPolicyObserverRegistrar::ConfigurationPolicyObserverRegistrar() {} + +ConfigurationPolicyObserverRegistrar::~ConfigurationPolicyObserverRegistrar() { + RemoveAll(); +} + +void ConfigurationPolicyObserverRegistrar::Init( + ConfigurationPolicyProvider* provider) { + provider_ = provider; +} + +void ConfigurationPolicyObserverRegistrar::AddObserver( + ConfigurationPolicyProvider::Observer* observer) { + observers_.push_back(observer); + provider_->AddObserver(observer); +} + +void ConfigurationPolicyObserverRegistrar::RemoveObserver( + ConfigurationPolicyProvider::Observer* observer) { + std::remove(observers_.begin(), observers_.end(), observer); + provider_->RemoveObserver(observer); +} + +void ConfigurationPolicyObserverRegistrar::RemoveAll() { + for (std::vector<ConfigurationPolicyProvider::Observer*>::iterator it = + observers_.begin(); it != observers_.end(); ++it) { + provider_->RemoveObserver(*it); + } + observers_.clear(); +} + +// Class ConfigurationPolicyProvider. + ConfigurationPolicyProvider::ConfigurationPolicyProvider( const PolicyDefinitionList* policy_list) : policy_definition_list_(policy_list) { @@ -16,15 +50,8 @@ ConfigurationPolicyProvider::ConfigurationPolicyProvider( ConfigurationPolicyProvider::~ConfigurationPolicyProvider() {} -void ConfigurationPolicyProvider::NotifyStoreOfPolicyChange() { - NotificationService::current()->Notify( - NotificationType::POLICY_CHANGED, - Source<ConfigurationPolicyProvider>(this), - NotificationService::NoDetails()); -} - void ConfigurationPolicyProvider::DecodePolicyValueTree( - DictionaryValue* policies, + const DictionaryValue* policies, ConfigurationPolicyStoreInterface* store) { const PolicyDefinitionList* policy_list(policy_definition_list()); for (const PolicyDefinitionList::Entry* i = policy_list->begin; diff --git a/chrome/browser/policy/configuration_policy_provider.h b/chrome/browser/policy/configuration_policy_provider.h index e3989b9..5639235 100644 --- a/chrome/browser/policy/configuration_policy_provider.h +++ b/chrome/browser/policy/configuration_policy_provider.h @@ -21,6 +21,12 @@ namespace policy { // etc.) should implement a subclass of this class. class ConfigurationPolicyProvider { public: + class Observer { + public: + virtual ~Observer() {} + virtual void OnUpdatePolicy() = 0; + }; + // Used for static arrays of policy values that is used to initialize an // instance of the ConfigurationPolicyProvider. struct PolicyDefinitionList { @@ -38,29 +44,35 @@ class ConfigurationPolicyProvider { virtual ~ConfigurationPolicyProvider(); - // Must be implemented by provider subclasses to specify the - // provider-specific policy decisions. The preference service - // invokes this |Provide| method when it needs a policy - // provider to specify its policy choices. In |Provide|, - // the |ConfigurationPolicyProvider| must make calls to the - // |Apply| method of |store| to apply specific policies. - // Returns true if the policy could be provided, otherwise false. + // Must be implemented by provider subclasses to specify the provider-specific + // policy decisions. The preference service invokes this |Provide| method when + // it needs a policy provider to specify its policy choices. In |Provide|, the + // |ConfigurationPolicyProvider| must make calls to the |Apply| method of + // |store| to apply specific policies. Returns true if the policy could be + // provided, otherwise false. virtual bool Provide(ConfigurationPolicyStoreInterface* store) = 0; - // Called by the subclass provider at any time to indicate that the currently - // applied policy is not longer current. A policy refresh will be initiated as - // soon as possible. - virtual void NotifyStoreOfPolicyChange(); + // Check whether this provider has completed initialization. This is used to + // detect whether initialization is done in case providers implementations + // need to do asynchronous operations for initialization. + virtual bool IsInitializationComplete() const { return true; } + protected: // Decodes the value tree and writes the configuration to the given |store|. - void DecodePolicyValueTree(DictionaryValue* policies, + void DecodePolicyValueTree(const DictionaryValue* policies, ConfigurationPolicyStoreInterface* store); - protected: + const PolicyDefinitionList* policy_definition_list() const { return policy_definition_list_; } private: + friend class ConfigurationPolicyObserverRegistrar; + + virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) = 0; + virtual void RemoveObserver( + ConfigurationPolicyProvider::Observer* observer) = 0; + // Contains the default mapping from policy values to the actual names. const ConfigurationPolicyProvider::PolicyDefinitionList* policy_definition_list_; @@ -69,6 +81,22 @@ class ConfigurationPolicyProvider { DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProvider); }; +// Manages observers for a ConfigurationPolicyProvider. Is used to register +// observers, and automatically removes them upon destruction. +class ConfigurationPolicyObserverRegistrar { + public: + ConfigurationPolicyObserverRegistrar(); + ~ConfigurationPolicyObserverRegistrar(); + void Init(ConfigurationPolicyProvider* provider); + void AddObserver(ConfigurationPolicyProvider::Observer* observer); + void RemoveObserver(ConfigurationPolicyProvider::Observer* observer); + void RemoveAll(); + private: + ConfigurationPolicyProvider* provider_; + std::vector<ConfigurationPolicyProvider::Observer*> observers_; + DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyObserverRegistrar); +}; + } // namespace policy #endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_H_ diff --git a/chrome/browser/policy/configuration_policy_provider_delegate_win.cc b/chrome/browser/policy/configuration_policy_provider_delegate_win.cc new file mode 100644 index 0000000..68947de --- /dev/null +++ b/chrome/browser/policy/configuration_policy_provider_delegate_win.cc @@ -0,0 +1,160 @@ +// 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/configuration_policy_provider_delegate_win.h" + +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/win/registry.h" +#include "chrome/common/policy_constants.h" + +using base::win::RegKey; + +namespace { + +bool ReadRegistryStringValue(RegKey* key, const string16& name, + string16* result) { + DWORD value_size = 0; + DWORD key_type = 0; + scoped_array<uint8> buffer; + + if (!key->ReadValue(name.c_str(), 0, &value_size, &key_type)) + return false; + if (key_type != REG_SZ) + return false; + + // According to the Microsoft documentation, the string + // buffer may not be explicitly 0-terminated. Allocate a + // slightly larger buffer and pre-fill to zeros to guarantee + // the 0-termination. + buffer.reset(new uint8[value_size + 2]); + memset(buffer.get(), 0, value_size + 2); + key->ReadValue(name.c_str(), buffer.get(), &value_size, NULL); + result->assign(reinterpret_cast<const wchar_t*>(buffer.get())); + return true; +} + +} // namespace + +namespace policy { + +ConfigurationPolicyProviderDelegateWin::ConfigurationPolicyProviderDelegateWin( + const ConfigurationPolicyProvider::PolicyDefinitionList* + policy_definition_list) + : policy_definition_list_(policy_definition_list) { +} + +DictionaryValue* ConfigurationPolicyProviderDelegateWin::Load() { + DictionaryValue* result = new DictionaryValue(); + const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current; + for (current = policy_definition_list_->begin; + current != policy_definition_list_->end; + ++current) { + const string16 name(ASCIIToUTF16(current->name)); + switch (current->value_type) { + case Value::TYPE_STRING: { + string16 string_value; + if (GetRegistryPolicyString(name, &string_value)) { + result->SetString(current->name, string_value); + } + break; + } + case Value::TYPE_LIST: { + scoped_ptr<ListValue> list_value(new ListValue); + if (GetRegistryPolicyStringList(name, list_value.get())) + result->Set(current->name, list_value.release()); + break; + } + case Value::TYPE_BOOLEAN: { + bool bool_value; + if (GetRegistryPolicyBoolean(name, &bool_value)) { + result->SetBoolean(current->name, bool_value); + } + break; + } + case Value::TYPE_INTEGER: { + uint32 int_value; + if (GetRegistryPolicyInteger(name, &int_value)) { + result->SetInteger(current->name, int_value); + } + break; + } + default: + NOTREACHED(); + } + } + return result; +} + +bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyString( + const string16& name, string16* result) const { + string16 path = string16(kRegistrySubKey); + RegKey policy_key; + // First try the global policy. + if (policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) { + if (ReadRegistryStringValue(&policy_key, name, result)) + return true; + policy_key.Close(); + } + // Fall back on user-specific policy. + if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ)) + return false; + return ReadRegistryStringValue(&policy_key, name, result); +} + +bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyStringList( + const string16& key, ListValue* result) const { + string16 path = string16(kRegistrySubKey); + path += ASCIIToUTF16("\\") + key; + RegKey policy_key; + if (!policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) { + policy_key.Close(); + // Fall back on user-specific policy. + if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ)) + return false; + } + string16 policy_string; + int index = 0; + while (ReadRegistryStringValue(&policy_key, base::IntToString16(++index), + &policy_string)) { + result->Append(Value::CreateStringValue(policy_string)); + } + return true; +} + +bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyBoolean( + const string16& value_name, bool* result) const { + DWORD value; + RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ); + if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) { + *result = value != 0; + return true; + } + + RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ); + if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) { + *result = value != 0; + return true; + } + return false; +} + +bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyInteger( + const string16& value_name, uint32* result) const { + DWORD value; + RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ); + if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) { + *result = value; + return true; + } + + RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ); + if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) { + *result = value; + return true; + } + return false; +} + +} // namespace policy diff --git a/chrome/browser/policy/configuration_policy_provider_delegate_win.h b/chrome/browser/policy/configuration_policy_provider_delegate_win.h new file mode 100644 index 0000000..63d36b2 --- /dev/null +++ b/chrome/browser/policy/configuration_policy_provider_delegate_win.h @@ -0,0 +1,47 @@ +// 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. + +#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_DELEGATE_WIN_H_ +#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_DELEGATE_WIN_H_ +#pragma once + +#include "chrome/browser/policy/asynchronous_policy_provider.h" + +namespace policy { + +class ConfigurationPolicyProviderDelegateWin + : public AsynchronousPolicyProvider::Delegate { + public: + ConfigurationPolicyProviderDelegateWin( + const ConfigurationPolicyProvider::PolicyDefinitionList* + policy_definition_list); + virtual ~ConfigurationPolicyProviderDelegateWin() {} + + // AsynchronousPolicyProvider::Delegate overrides: + virtual DictionaryValue* Load(); + + private: + // Methods to perform type-specific policy lookups in the registry. + // HKLM is checked first, then HKCU. + + // Reads a string registry value |name| at the specified |key| and puts the + // resulting string in |result|. + bool GetRegistryPolicyString(const string16& name, string16* result) const; + // Gets a list value contained under |key| one level below the policy root. + bool GetRegistryPolicyStringList(const string16& key, + ListValue* result) const; + bool GetRegistryPolicyBoolean(const string16& value_name, + bool* result) const; + bool GetRegistryPolicyInteger(const string16& value_name, + uint32* result) const; + + const ConfigurationPolicyProvider::PolicyDefinitionList* + policy_definition_list_; + + DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderDelegateWin); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_DELEGATE_WIN_H_ diff --git a/chrome/browser/policy/configuration_policy_provider_mac.cc b/chrome/browser/policy/configuration_policy_provider_mac.cc index 62b7436..b8b6011 100644 --- a/chrome/browser/policy/configuration_policy_provider_mac.cc +++ b/chrome/browser/policy/configuration_policy_provider_mac.cc @@ -34,15 +34,15 @@ static FilePath GetManagedPolicyPath() { return path.Append(base::SysCFStringRefToUTF8(bundle_id) + ".plist"); } -MacPreferencesPolicyLoader::MacPreferencesPolicyLoader( +MacPreferencesPolicyProviderDelegate::MacPreferencesPolicyProviderDelegate( MacPreferences* preferences, const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list) - : FileBasedPolicyProvider::Delegate(GetManagedPolicyPath()), + : FileBasedPolicyProvider::ProviderDelegate(GetManagedPolicyPath()), policy_list_(policy_list), preferences_(preferences) { } -DictionaryValue* MacPreferencesPolicyLoader::Load() { +DictionaryValue* MacPreferencesPolicyProviderDelegate::Load() { preferences_->AppSynchronize(kCFPreferencesCurrentApplication); DictionaryValue* policy = new DictionaryValue; @@ -110,7 +110,7 @@ DictionaryValue* MacPreferencesPolicyLoader::Load() { return policy; } -base::Time MacPreferencesPolicyLoader::GetLastModification() { +base::Time MacPreferencesPolicyProviderDelegate::GetLastModification() { base::PlatformFileInfo file_info; if (!file_util::GetFileInfo(config_file_path(), &file_info) || file_info.is_directory) { @@ -123,14 +123,16 @@ base::Time MacPreferencesPolicyLoader::GetLastModification() { ConfigurationPolicyProviderMac::ConfigurationPolicyProviderMac( const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list) : FileBasedPolicyProvider(policy_list, - new MacPreferencesPolicyLoader(new MacPreferences, policy_list)) { + new MacPreferencesPolicyProviderDelegate(new MacPreferences, + policy_list)) { } ConfigurationPolicyProviderMac::ConfigurationPolicyProviderMac( const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list, MacPreferences* preferences) : FileBasedPolicyProvider(policy_list, - new MacPreferencesPolicyLoader(preferences, policy_list)) { + new MacPreferencesPolicyProviderDelegate(preferences, + policy_list)) { } } // namespace policy diff --git a/chrome/browser/policy/configuration_policy_provider_mac.h b/chrome/browser/policy/configuration_policy_provider_mac.h index d804500..9332e2b 100644 --- a/chrome/browser/policy/configuration_policy_provider_mac.h +++ b/chrome/browser/policy/configuration_policy_provider_mac.h @@ -13,11 +13,12 @@ namespace policy { -// A policy loader implementation that read Mac OS X's managed preferences. -class MacPreferencesPolicyLoader : public FileBasedPolicyProvider::Delegate { +// A provider delegate implementation that reads Mac OS X's managed preferences. +class MacPreferencesPolicyProviderDelegate + : public FileBasedPolicyProvider::ProviderDelegate { public: // Takes ownership of |preferences|. - MacPreferencesPolicyLoader( + MacPreferencesPolicyProviderDelegate( MacPreferences* preferences, const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list); @@ -35,7 +36,7 @@ class MacPreferencesPolicyLoader : public FileBasedPolicyProvider::Delegate { scoped_ptr<MacPreferences> preferences_; - DISALLOW_COPY_AND_ASSIGN(MacPreferencesPolicyLoader); + DISALLOW_COPY_AND_ASSIGN(MacPreferencesPolicyProviderDelegate); }; // An implementation of |ConfigurationPolicyProvider| using the mechanism diff --git a/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc b/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc index 5690375..345a3f6 100644 --- a/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc +++ b/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc @@ -233,8 +233,8 @@ INSTANTIATE_TEST_CASE_P( kPolicyDefaultSearchProviderEncodings, key::kDefaultSearchProviderEncodings), PolicyTestParams::ForIntegerPolicy( - kPolicyProxyServerMode, - key::kProxyServerMode), + kPolicyProxyMode, + key::kProxyMode), PolicyTestParams::ForStringPolicy( kPolicyProxyServer, key::kProxyServer), diff --git a/chrome/browser/policy/configuration_policy_provider_win.cc b/chrome/browser/policy/configuration_policy_provider_win.cc index 8f86973..df336d3 100644 --- a/chrome/browser/policy/configuration_policy_provider_win.cc +++ b/chrome/browser/policy/configuration_policy_provider_win.cc @@ -4,285 +4,22 @@ #include "chrome/browser/policy/configuration_policy_provider_win.h" -#include <userenv.h> - -#include <algorithm> - -#include "base/logging.h" -#include "base/object_watcher.h" -#include "base/scoped_ptr.h" -#include "base/string_number_conversions.h" -#include "base/string_piece.h" -#include "base/string_util.h" -#include "base/sys_string_conversions.h" -#include "base/utf_string_conversions.h" -#include "base/values.h" -#include "base/win/registry.h" -#include "chrome/common/policy_constants.h" - -using base::win::RegKey; +#include "chrome/browser/policy/asynchronous_policy_provider.h" +#include "chrome/browser/policy/configuration_policy_loader_win.h" +#include "chrome/browser/policy/configuration_policy_provider_delegate_win.h" namespace policy { -namespace { - -bool ReadRegistryStringValue(RegKey* key, const string16& name, - string16* result) { - DWORD value_size = 0; - DWORD key_type = 0; - scoped_array<uint8> buffer; - - if (!key->ReadValue(name.c_str(), 0, &value_size, &key_type)) - return false; - if (key_type != REG_SZ) - return false; - - // According to the Microsoft documentation, the string - // buffer may not be explicitly 0-terminated. Allocate a - // slightly larger buffer and pre-fill to zeros to guarantee - // the 0-termination. - buffer.reset(new uint8[value_size + 2]); - memset(buffer.get(), 0, value_size + 2); - key->ReadValue(name.c_str(), buffer.get(), &value_size, NULL); - result->assign(reinterpret_cast<const wchar_t*>(buffer.get())); - return true; -} - -} // namespace - // Period at which to run the reload task in case the group policy change // watchers fail. const int kReloadIntervalMinutes = 15; -ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher:: - GroupPolicyChangeWatcher( - base::WeakPtr<ConfigurationPolicyProviderWin> provider, - int reload_interval_minutes) - : provider_(provider), - user_policy_changed_event_(false, false), - machine_policy_changed_event_(false, false), - user_policy_watcher_failed_(false), - machine_policy_watcher_failed_(false), - reload_interval_minutes_(reload_interval_minutes), - reload_task_(NULL) { - if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) { - PLOG(WARNING) << "Failed to register user group policy notification"; - user_policy_watcher_failed_ = true; - } - if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) { - PLOG(WARNING) << "Failed to register machine group policy notification."; - machine_policy_watcher_failed_ = true; - } -} - -ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher:: - ~GroupPolicyChangeWatcher() { - if (MessageLoop::current()) - MessageLoop::current()->RemoveDestructionObserver(this); - DCHECK(!reload_task_); -} - -void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Start() { - MessageLoop::current()->AddDestructionObserver(this); - SetupWatches(); -} - -void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Stop() { - user_policy_watcher_.StopWatching(); - machine_policy_watcher_.StopWatching(); - if (reload_task_) { - reload_task_->Cancel(); - reload_task_ = NULL; - } -} - -void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::SetupWatches() { - if (reload_task_) { - reload_task_->Cancel(); - reload_task_ = NULL; - } - - if (!user_policy_watcher_failed_) { - if (!user_policy_watcher_.GetWatchedObject() && - !user_policy_watcher_.StartWatching( - user_policy_changed_event_.handle(), this)) { - LOG(WARNING) << "Failed to start watch for user policy change event"; - user_policy_watcher_failed_ = true; - } - } - if (!machine_policy_watcher_failed_) { - if (!machine_policy_watcher_.GetWatchedObject() && - !machine_policy_watcher_.StartWatching( - machine_policy_changed_event_.handle(), this)) { - LOG(WARNING) << "Failed to start watch for machine policy change event"; - machine_policy_watcher_failed_ = true; - } - } - - if (user_policy_watcher_failed_ || machine_policy_watcher_failed_) { - reload_task_ = - NewRunnableMethod(this, &GroupPolicyChangeWatcher::ReloadFromTask); - int64 delay = - base::TimeDelta::FromMinutes(reload_interval_minutes_).InMilliseconds(); - MessageLoop::current()->PostDelayedTask(FROM_HERE, reload_task_, delay); - } -} - -void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Reload() { - if (provider_.get()) - provider_->NotifyStoreOfPolicyChange(); - SetupWatches(); -} - -void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher:: - ReloadFromTask() { - // Make sure to not call Cancel() on the task, since it might hold the last - // reference that keeps this object alive. - reload_task_ = NULL; - Reload(); -} - -void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher:: - OnObjectSignaled(HANDLE object) { - DCHECK(object == user_policy_changed_event_.handle() || - object == machine_policy_changed_event_.handle()) - << "unexpected object signaled policy reload, obj = " - << std::showbase << std::hex << object; - Reload(); -} - -void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher:: - WillDestroyCurrentMessageLoop() { - reload_task_ = NULL; - MessageLoop::current()->RemoveDestructionObserver(this); -} - ConfigurationPolicyProviderWin::ConfigurationPolicyProviderWin( const PolicyDefinitionList* policy_list) - : ConfigurationPolicyProvider(policy_list) { - watcher_ = new GroupPolicyChangeWatcher(this->AsWeakPtr(), - kReloadIntervalMinutes); - watcher_->Start(); -} - -ConfigurationPolicyProviderWin::~ConfigurationPolicyProviderWin() { - watcher_->Stop(); -} - -bool ConfigurationPolicyProviderWin::GetRegistryPolicyString( - const string16& name, string16* result) const { - string16 path = string16(kRegistrySubKey); - RegKey policy_key; - // First try the global policy. - if (policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) { - if (ReadRegistryStringValue(&policy_key, name, result)) - return true; - policy_key.Close(); - } - // Fall back on user-specific policy. - if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ)) - return false; - return ReadRegistryStringValue(&policy_key, name, result); -} - -bool ConfigurationPolicyProviderWin::GetRegistryPolicyStringList( - const string16& key, ListValue* result) const { - string16 path = string16(kRegistrySubKey); - path += ASCIIToUTF16("\\") + key; - RegKey policy_key; - if (!policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) { - policy_key.Close(); - // Fall back on user-specific policy. - if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ)) - return false; - } - string16 policy_string; - int index = 0; - while (ReadRegistryStringValue(&policy_key, base::IntToString16(++index), - &policy_string)) { - result->Append(Value::CreateStringValue(policy_string)); - } - return true; -} - -bool ConfigurationPolicyProviderWin::GetRegistryPolicyBoolean( - const string16& value_name, bool* result) const { - DWORD value; - RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ); - if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) { - *result = value != 0; - return true; - } - - RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ); - if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) { - *result = value != 0; - return true; - } - return false; -} - -bool ConfigurationPolicyProviderWin::GetRegistryPolicyInteger( - const string16& value_name, uint32* result) const { - DWORD value; - RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ); - if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) { - *result = value; - return true; - } - - RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ); - if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) { - *result = value; - return true; - } - return false; -} - -bool ConfigurationPolicyProviderWin::Provide( - ConfigurationPolicyStoreInterface* store) { - const PolicyDefinitionList* policy_list(policy_definition_list()); - for (const PolicyDefinitionList::Entry* current = policy_list->begin; - current != policy_list->end; ++current) { - std::wstring name = UTF8ToWide(current->name); - switch (current->value_type) { - case Value::TYPE_STRING: { - std::wstring string_value; - if (GetRegistryPolicyString(name.c_str(), &string_value)) { - store->Apply(current->policy_type, - Value::CreateStringValue(string_value)); - } - break; - } - case Value::TYPE_LIST: { - scoped_ptr<ListValue> list_value(new ListValue); - if (GetRegistryPolicyStringList(name.c_str(), list_value.get())) - store->Apply(current->policy_type, list_value.release()); - break; - } - case Value::TYPE_BOOLEAN: { - bool bool_value; - if (GetRegistryPolicyBoolean(name.c_str(), &bool_value)) { - store->Apply(current->policy_type, - Value::CreateBooleanValue(bool_value)); - } - break; - } - case Value::TYPE_INTEGER: { - uint32 int_value; - if (GetRegistryPolicyInteger(name.c_str(), &int_value)) { - store->Apply(current->policy_type, - Value::CreateIntegerValue(int_value)); - } - break; - } - default: - NOTREACHED(); - return false; - } - } - - return true; -} + : AsynchronousPolicyProvider( + policy_list, + new ConfigurationPolicyLoaderWin( + new ConfigurationPolicyProviderDelegateWin(policy_list), + kReloadIntervalMinutes)) {} } // namespace policy diff --git a/chrome/browser/policy/configuration_policy_provider_win.h b/chrome/browser/policy/configuration_policy_provider_win.h index c2d5509..31e4a2b 100644 --- a/chrome/browser/policy/configuration_policy_provider_win.h +++ b/chrome/browser/policy/configuration_policy_provider_win.h @@ -6,19 +6,7 @@ #define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_WIN_H_ #pragma once -#include "base/object_watcher.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" -#include "base/waitable_event.h" -#include "base/weak_ptr.h" -#include "chrome/browser/policy/configuration_policy_store_interface.h" -#include "chrome/browser/policy/configuration_policy_provider.h" - -namespace base { -namespace win { -class RegKey; -} // namespace win -} // namespace base +#include "chrome/browser/policy/asynchronous_policy_provider.h" namespace policy { @@ -28,89 +16,14 @@ namespace policy { // On a managed machine in a domain, this portion of the registry is // periodically updated by the Windows Group Policy machinery to contain // the latest version of the policy set by administrators. -class ConfigurationPolicyProviderWin - : public ConfigurationPolicyProvider, - public base::SupportsWeakPtr<ConfigurationPolicyProviderWin> { +class ConfigurationPolicyProviderWin : public AsynchronousPolicyProvider { public: - // Keeps watch on Windows Group Policy notification event to trigger a policy - // reload when Group Policy changes. This class is reference counted to - // facilitate timer-based reloads through the message loop. It is not safe to - // access GroupPolicyChangeWatcher concurrently from multiple threads. - class GroupPolicyChangeWatcher - : public base::ObjectWatcher::Delegate, - public MessageLoop::DestructionObserver, - public base::RefCountedThreadSafe<GroupPolicyChangeWatcher> { - public: - GroupPolicyChangeWatcher( - base::WeakPtr<ConfigurationPolicyProviderWin> provider, - int reload_interval_minutes); - virtual ~GroupPolicyChangeWatcher(); - - // Start watching. - void Start(); - - // Stop any pending watch activity in order to allow for timely shutdown. - void Stop(); - - private: - // Updates the watchers and schedules the reload task if appropriate. - void SetupWatches(); - - // Post a reload notification and update the watch machinery. - void Reload(); - - // Called for timer-based refresh from the message loop. - void ReloadFromTask(); - - // ObjectWatcher::Delegate implementation: - virtual void OnObjectSignaled(HANDLE object); - - // MessageLoop::DestructionObserver implementation: - virtual void WillDestroyCurrentMessageLoop(); - - base::WeakPtr<ConfigurationPolicyProviderWin> provider_; - base::WaitableEvent user_policy_changed_event_; - base::WaitableEvent machine_policy_changed_event_; - base::ObjectWatcher user_policy_watcher_; - base::ObjectWatcher machine_policy_watcher_; - bool user_policy_watcher_failed_; - bool machine_policy_watcher_failed_; - - // Period to schedule the reload task at. - int reload_interval_minutes_; - - // A reference to a delayed task for timer-based reloading. - CancelableTask* reload_task_; - }; - explicit ConfigurationPolicyProviderWin( const PolicyDefinitionList* policy_list); - virtual ~ConfigurationPolicyProviderWin(); - - // ConfigurationPolicyProvider method overrides: - virtual bool Provide(ConfigurationPolicyStoreInterface* store); - - protected: - // The sub key path for Chromium's Group Policy information in the - // Windows registry. - static const wchar_t kPolicyRegistrySubKey[]; + virtual ~ConfigurationPolicyProviderWin() {} private: - scoped_refptr<GroupPolicyChangeWatcher> watcher_; - - // Methods to perform type-specific policy lookups in the registry. - // HKLM is checked first, then HKCU. - - // Reads a string registry value |name| at the specified |key| and puts the - // resulting string in |result|. - bool GetRegistryPolicyString(const string16& name, string16* result) const; - // Gets a list value contained under |key| one level below the policy root. - bool GetRegistryPolicyStringList(const string16& key, - ListValue* result) const; - bool GetRegistryPolicyBoolean(const string16& value_name, - bool* result) const; - bool GetRegistryPolicyInteger(const string16& value_name, - uint32* result) const; + DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderWin); }; } // namespace policy diff --git a/chrome/browser/policy/configuration_policy_provider_win_unittest.cc b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc index 39c4dce..beed450 100644 --- a/chrome/browser/policy/configuration_policy_provider_win_unittest.cc +++ b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc @@ -3,15 +3,17 @@ // found in the LICENSE file. #include <gtest/gtest.h> - #include <windows.h> +#include "base/message_loop.h" #include "base/scoped_ptr.h" #include "base/stl_util-inl.h" #include "base/string_number_conversions.h" #include "base/string_piece.h" #include "base/utf_string_conversions.h" #include "base/win/registry.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/asynchronous_policy_loader.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/configuration_policy_provider_win.h" #include "chrome/browser/policy/mock_configuration_policy_store.h" @@ -151,13 +153,16 @@ class ConfigurationPolicyProviderWinTest scoped_ptr<MockConfigurationPolicyStore> store_; scoped_ptr<ConfigurationPolicyProviderWin> provider_; - private: // A message loop must be declared and instantiated for these tests, // because Windows policy provider create WaitableEvents and // ObjectWatchers that require the tests to have a MessageLoop associated // with the thread executing the tests. MessageLoop loop_; + private: + BrowserThread ui_thread_; + BrowserThread file_thread_; + // Keys are created for the lifetime of a test to contain // the sandboxed HKCU and HKLM hives, respectively. RegKey temp_hkcu_hive_key_; @@ -165,7 +170,9 @@ class ConfigurationPolicyProviderWinTest }; ConfigurationPolicyProviderWinTest::ConfigurationPolicyProviderWinTest() - : temp_hklm_hive_key_(HKEY_CURRENT_USER, kUnitTestMachineOverrideSubKey, + : ui_thread_(BrowserThread::UI, &loop_), + file_thread_(BrowserThread::FILE, &loop_), + temp_hklm_hive_key_(HKEY_CURRENT_USER, kUnitTestMachineOverrideSubKey, KEY_READ), temp_hkcu_hive_key_(HKEY_CURRENT_USER, kUnitTestUserOverrideSubKey, KEY_READ) { @@ -194,6 +201,7 @@ void ConfigurationPolicyProviderWinTest::SetUp() { void ConfigurationPolicyProviderWinTest::TearDown() { DeactivateOverrides(); DeleteRegistrySandbox(); + loop_.RunAllPending(); } void ConfigurationPolicyProviderWinTest::ActivateOverrides() { @@ -299,6 +307,8 @@ TEST_P(ConfigurationPolicyProviderWinTest, InvalidValue) { WriteInvalidValue(HKEY_CURRENT_USER, GetParam().policy_name(), GetParam().hkcu_value()); + provider_->loader()->Reload(); + loop_.RunAllPending(); provider_->Provide(store_.get()); EXPECT_TRUE(store_->policy_map().empty()); } @@ -307,6 +317,8 @@ TEST_P(ConfigurationPolicyProviderWinTest, HKLM) { WriteValue(HKEY_LOCAL_MACHINE, GetParam().policy_name(), GetParam().hklm_value()); + provider_->loader()->Reload(); + loop_.RunAllPending(); provider_->Provide(store_.get()); const Value* value = store_->Get(GetParam().type()); ASSERT_TRUE(value); @@ -317,6 +329,8 @@ TEST_P(ConfigurationPolicyProviderWinTest, HKCU) { WriteValue(HKEY_CURRENT_USER, GetParam().policy_name(), GetParam().hkcu_value()); + provider_->loader()->Reload(); + loop_.RunAllPending(); provider_->Provide(store_.get()); const Value* value = store_->Get(GetParam().type()); ASSERT_TRUE(value); @@ -330,6 +344,8 @@ TEST_P(ConfigurationPolicyProviderWinTest, HKLMOverHKCU) { WriteValue(HKEY_CURRENT_USER, GetParam().policy_name(), GetParam().hkcu_value()); + provider_->loader()->Reload(); + loop_.RunAllPending(); provider_->Provide(store_.get()); const Value* value = store_->Get(GetParam().type()); ASSERT_TRUE(value); @@ -375,8 +391,8 @@ INSTANTIATE_TEST_CASE_P( kPolicyDefaultSearchProviderEncodings, key::kDefaultSearchProviderEncodings), PolicyTestParams::ForIntegerPolicy( - kPolicyProxyServerMode, - key::kProxyServerMode), + kPolicyProxyMode, + key::kProxyMode), PolicyTestParams::ForStringPolicy( kPolicyProxyServer, key::kProxyServer), diff --git a/chrome/browser/policy/configuration_policy_store_interface.h b/chrome/browser/policy/configuration_policy_store_interface.h index b47069e..b6d1f3b 100644 --- a/chrome/browser/policy/configuration_policy_store_interface.h +++ b/chrome/browser/policy/configuration_policy_store_interface.h @@ -25,7 +25,7 @@ enum ConfigurationPolicyType { kPolicyDefaultSearchProviderIconURL, kPolicyDefaultSearchProviderEncodings, kPolicyDisableSpdy, - kPolicyProxyServerMode, + kPolicyProxyMode, kPolicyProxyServer, kPolicyProxyPacUrl, kPolicyProxyBypassList, @@ -56,6 +56,8 @@ enum ConfigurationPolicyType { kPolicyDefaultJavaScriptSetting, kPolicyDefaultPluginsSetting, kPolicyDefaultPopupsSetting, + kPolicyDefaultNotificationSetting, + kPolicyDefaultGeolocationSetting, kPolicyExtensionInstallForceList, kPolicyChromeOsLockOnIdleSuspend, kPolicyAuthSchemes, @@ -67,10 +69,24 @@ enum ConfigurationPolicyType { kPolicyDisable3DAPIs }; -static const int kPolicyNoProxyServerMode = 0; -static const int kPolicyAutoDetectProxyMode = 1; -static const int kPolicyManuallyConfiguredProxyMode = 2; -static const int kPolicyUseSystemProxyMode = 3; + +// Constants for the "Proxy Server Mode" defined in the policies. +// Note that these diverge from internal presentation defined in +// ProxyPrefs::ProxyMode for legacy reasons. The following four +// PolicyProxyModeType types were not very precise and had overlapping use +// cases. +enum PolicyProxyModeType { + // Disable Proxy, connect directly. + kPolicyNoProxyServerMode = 0, + // Auto detect proxy or use specific PAC script if given. + kPolicyAutoDetectProxyMode = 1, + // Use manually configured proxy servers (fixed servers). + kPolicyManuallyConfiguredProxyMode = 2, + // Use system proxy server. + kPolicyUseSystemProxyMode = 3, + + MODE_COUNT +}; // An abstract super class for policy stores that provides a method that can be // called by a |ConfigurationPolicyProvider| to specify a policy. diff --git a/chrome/browser/policy/device_management_policy_cache.cc b/chrome/browser/policy/device_management_policy_cache.cc index 81af0f4..ab5dd15 100644 --- a/chrome/browser/policy/device_management_policy_cache.cc +++ b/chrome/browser/policy/device_management_policy_cache.cc @@ -70,6 +70,8 @@ DeviceManagementPolicyCache::DeviceManagementPolicyCache( is_device_unmanaged_(false) { } +DeviceManagementPolicyCache::~DeviceManagementPolicyCache() {} + void DeviceManagementPolicyCache::LoadPolicyFromFile() { if (!file_util::PathExists(backing_file_path_) || fresh_policy_) return; diff --git a/chrome/browser/policy/device_management_policy_cache.h b/chrome/browser/policy/device_management_policy_cache.h index 86ae845..9c09a07 100644 --- a/chrome/browser/policy/device_management_policy_cache.h +++ b/chrome/browser/policy/device_management_policy_cache.h @@ -28,6 +28,7 @@ namespace em = enterprise_management; class DeviceManagementPolicyCache { public: explicit DeviceManagementPolicyCache(const FilePath& backing_file_path); + ~DeviceManagementPolicyCache(); // Loads policy information from the backing file. Non-existing or erroneous // cache files are ignored. diff --git a/chrome/browser/policy/device_management_policy_provider.cc b/chrome/browser/policy/device_management_policy_provider.cc index 9fa7f58..1a1f0c2 100644 --- a/chrome/browser/policy/device_management_policy_provider.cc +++ b/chrome/browser/policy/device_management_policy_provider.cc @@ -10,10 +10,10 @@ #include "base/rand_util.h" #include "base/task.h" #include "chrome/browser/browser_thread.h" -#include "chrome/browser/profile.h" #include "chrome/browser/policy/device_management_backend.h" #include "chrome/browser/policy/device_management_policy_cache.h" #include "chrome/browser/policy/proto/device_management_constants.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/notification_service.h" @@ -117,10 +117,14 @@ bool DeviceManagementPolicyProvider::Provide( return true; } +bool DeviceManagementPolicyProvider::IsInitializationComplete() const { + return !waiting_for_initial_policies_; +} + void DeviceManagementPolicyProvider::HandlePolicyResponse( const em::DevicePolicyResponse& response) { if (cache_->SetPolicy(response)) - NotifyStoreOfPolicyChange(); + NotifyCloudPolicyUpdate(); policy_request_pending_ = false; // Reset the error delay since policy fetching succeeded this time. policy_refresh_error_delay_ms_ = kPolicyRefreshErrorDelayInMilliseconds; @@ -185,6 +189,22 @@ void DeviceManagementPolicyProvider::Shutdown() { token_fetcher_->Shutdown(); } +void DeviceManagementPolicyProvider::AddObserver( + ConfigurationPolicyProvider::Observer* observer) { + observer_list_.AddObserver(observer); +} + +void DeviceManagementPolicyProvider::RemoveObserver( + ConfigurationPolicyProvider::Observer* observer) { + observer_list_.RemoveObserver(observer); +} + +void DeviceManagementPolicyProvider::NotifyCloudPolicyUpdate() { + FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, + observer_list_, + OnUpdatePolicy()); +} + void DeviceManagementPolicyProvider::Initialize( DeviceManagementBackend* backend, Profile* profile, @@ -314,18 +334,10 @@ void DeviceManagementPolicyProvider::SetDeviceTokenFetcher( void DeviceManagementPolicyProvider::StopWaitingForInitialPolicies() { waiting_for_initial_policies_ = false; - // Send a CLOUD_POLICY_UPDATE notification to unblock ChromeOS logins that - // are waiting for an initial policy fetch to complete. + // Notify observers that initial policy fetch is complete. NotifyCloudPolicyUpdate(); } -void DeviceManagementPolicyProvider::NotifyCloudPolicyUpdate() const { - NotificationService::current()->Notify( - NotificationType::CLOUD_POLICY_UPDATE, - Source<DeviceManagementPolicyProvider>(this), - NotificationService::NoDetails()); -} - // static std::string DeviceManagementPolicyProvider::GetDeviceManagementURL() { return CommandLine::ForCurrentProcess()->GetSwitchValueASCII( diff --git a/chrome/browser/policy/device_management_policy_provider.h b/chrome/browser/policy/device_management_policy_provider.h index c7cdcbc..17edf82 100644 --- a/chrome/browser/policy/device_management_policy_provider.h +++ b/chrome/browser/policy/device_management_policy_provider.h @@ -9,6 +9,7 @@ #include <string> #include "base/file_path.h" +#include "base/observer_list.h" #include "base/scoped_ptr.h" #include "base/time.h" #include "base/weak_ptr.h" @@ -41,6 +42,7 @@ class DeviceManagementPolicyProvider // ConfigurationPolicyProvider implementation: virtual bool Provide(ConfigurationPolicyStoreInterface* store); + virtual bool IsInitializationComplete() const; // DevicePolicyResponseDelegate implementation: virtual void HandlePolicyResponse( @@ -48,17 +50,9 @@ class DeviceManagementPolicyProvider virtual void OnError(DeviceManagementBackend::ErrorCode code); // DeviceTokenFetcher::Observer implementation: - void OnTokenSuccess(); - void OnTokenError(); - void OnNotManaged(); - - // True if a policy request has been sent to the device management backend - // server and no response or error has yet been received. - bool IsPolicyRequestPending() const { return policy_request_pending_; } - - bool waiting_for_initial_policies() const { - return waiting_for_initial_policies_; - } + virtual void OnTokenSuccess(); + virtual void OnTokenError(); + virtual void OnNotManaged(); // Tells the provider that the passed in token service reference is about to // become invalid. @@ -96,6 +90,10 @@ class DeviceManagementPolicyProvider // of initialization that requires the IOThread. void InitializeAfterIOThreadExists(); + // ConfigurationPolicyProvider overrides: + virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer); + virtual void RemoveObserver(ConfigurationPolicyProvider::Observer* observer); + // Sends a request to the device manager backend to fetch policy if one isn't // already outstanding. void SendPolicyRequest(); @@ -112,8 +110,8 @@ class DeviceManagementPolicyProvider void StopWaitingForInitialPolicies(); - // Send a CLOUD_POLICY_UPDATE notification. - void NotifyCloudPolicyUpdate() const; + // Notify observers about a policy update. + void NotifyCloudPolicyUpdate(); // The path of the device token file. FilePath GetTokenPath(); @@ -135,6 +133,7 @@ class DeviceManagementPolicyProvider scoped_ptr<DeviceManagementPolicyCache> cache_; scoped_refptr<DeviceTokenFetcher> token_fetcher_; DeviceTokenFetcher::ObserverRegistrar registrar_; + ObserverList<ConfigurationPolicyProvider::Observer, true> observer_list_; FilePath storage_dir_; bool policy_request_pending_; bool refresh_task_pending_; diff --git a/chrome/browser/policy/device_management_policy_provider_unittest.cc b/chrome/browser/policy/device_management_policy_provider_unittest.cc index 3269531..4886f9d 100644 --- a/chrome/browser/policy/device_management_policy_provider_unittest.cc +++ b/chrome/browser/policy/device_management_policy_provider_unittest.cc @@ -8,16 +8,18 @@ #include "chrome/browser/browser_thread.h" #include "chrome/browser/net/gaia/token_service.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" #include "chrome/common/net/gaia/gaia_constants.h" +#include "chrome/common/notification_observer_mock.h" #include "chrome/common/notification_service.h" #include "chrome/common/policy_constants.h" -#include "chrome/test/mock_notification_observer.h" #include "chrome/test/testing_device_token_fetcher.h" #include "chrome/test/testing_profile.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" const char kTestToken[] = "device_policy_provider_test_auth_token"; @@ -28,6 +30,12 @@ using ::testing::_; using ::testing::InSequence; using ::testing::Mock; +class MockConfigurationPolicyObserver + : public ConfigurationPolicyProvider::Observer { + public: + MOCK_METHOD0(OnUpdatePolicy, void()); +}; + class DeviceManagementPolicyProviderTest : public testing::Test { public: DeviceManagementPolicyProviderTest() @@ -39,7 +47,7 @@ class DeviceManagementPolicyProviderTest : public testing::Test { virtual void SetUp() { profile_.reset(new TestingProfile); CreateNewProvider(); - EXPECT_TRUE(provider_->waiting_for_initial_policies()); + EXPECT_TRUE(waiting_for_initial_policies()); loop_.RunAllPending(); } @@ -99,7 +107,7 @@ class DeviceManagementPolicyProviderTest : public testing::Test { MockDeviceManagementBackendSucceedBooleanPolicy( key::kDisableSpdy, true)); SimulateSuccessfulLoginAndRunPending(); - EXPECT_FALSE(provider_->waiting_for_initial_policies()); + EXPECT_FALSE(waiting_for_initial_policies()); EXPECT_CALL(store, Apply(kPolicyDisableSpdy, _)).Times(1); provider_->Provide(&store); ASSERT_EQ(1U, store.policy_map().size()); @@ -111,6 +119,10 @@ class DeviceManagementPolicyProviderTest : public testing::Test { loop_.RunAllPending(); } + bool waiting_for_initial_policies() const { + return provider_->waiting_for_initial_policies_; + } + MockDeviceManagementBackend* backend_; // weak scoped_ptr<DeviceManagementPolicyProvider> provider_; @@ -136,14 +148,14 @@ TEST_F(DeviceManagementPolicyProviderTest, InitialProvideNoLogin) { EXPECT_CALL(store, Apply(_, _)).Times(0); provider_->Provide(&store); EXPECT_TRUE(store.policy_map().empty()); - EXPECT_TRUE(provider_->waiting_for_initial_policies()); + EXPECT_TRUE(waiting_for_initial_policies()); } // If the login is successful and there's no previously-fetched policy, the // policy should be fetched from the server and should be available the first // time the Provide method is called. TEST_F(DeviceManagementPolicyProviderTest, InitialProvideWithLogin) { - EXPECT_TRUE(provider_->waiting_for_initial_policies()); + EXPECT_TRUE(waiting_for_initial_policies()); SimulateSuccessfulInitialPolicyFetch(); } @@ -193,12 +205,11 @@ TEST_F(DeviceManagementPolicyProviderTest, SecondProvide) { // When policy is successfully fetched from the device management server, it // should force a policy refresh. TEST_F(DeviceManagementPolicyProviderTest, FetchTriggersRefresh) { - MockNotificationObserver observer; - NotificationRegistrar registrar; - registrar.Add(&observer, - NotificationType::POLICY_CHANGED, - NotificationService::AllSources()); - EXPECT_CALL(observer, Observe(_, _, _)).Times(1); + MockConfigurationPolicyObserver observer; + ConfigurationPolicyObserverRegistrar registrar; + registrar.Init(provider_.get()); + registrar.AddObserver(&observer); + EXPECT_CALL(observer, OnUpdatePolicy()).Times(1); SimulateSuccessfulInitialPolicyFetch(); } @@ -305,7 +316,7 @@ TEST_F(DeviceManagementPolicyProviderTest, UnmanagedDevice) { // (2) On restart, the provider should detect that this is not the first // login. CreateNewProvider(1000*1000, 0, 0, 0, 0); - EXPECT_FALSE(provider_->waiting_for_initial_policies()); + EXPECT_FALSE(waiting_for_initial_policies()); EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( diff --git a/chrome/browser/policy/device_management_service.cc b/chrome/browser/policy/device_management_service.cc index 05c8789..689c947 100644 --- a/chrome/browser/policy/device_management_service.cc +++ b/chrome/browser/policy/device_management_service.cc @@ -14,7 +14,6 @@ #include "net/proxy/proxy_service.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_status.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/io_thread.h" #include "chrome/browser/net/chrome_net_log.h" #include "chrome/browser/policy/device_management_backend_impl.h" diff --git a/chrome/browser/policy/device_management_service_browsertest.cc b/chrome/browser/policy/device_management_service_browsertest.cc index 6c07e9e..feed86f 100644 --- a/chrome/browser/policy/device_management_service_browsertest.cc +++ b/chrome/browser/policy/device_management_service_browsertest.cc @@ -3,11 +3,10 @@ // found in the LICENSE file. #include "base/message_loop.h" -#include "chrome/browser/browser_thread.h" #include "chrome/browser/policy/device_management_backend_mock.h" #include "chrome/browser/policy/device_management_service.h" #include "chrome/browser/policy/proto/device_management_constants.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/in_process_browser_test.h" #include "net/test/test_server.h" @@ -43,22 +42,22 @@ const char kServiceResponseUnregister[] = #define PROTO_STRING(name) (std::string(name, arraysize(name) - 1)) // Interceptor implementation that returns test data back to the service. -class CannedResponseInterceptor : public URLRequest::Interceptor { +class CannedResponseInterceptor : public net::URLRequest::Interceptor { public: CannedResponseInterceptor(const GURL& service_url, const std::string& response_data) : service_url_(service_url), response_data_(response_data) { - URLRequest::RegisterRequestInterceptor(this); + net::URLRequest::RegisterRequestInterceptor(this); } virtual ~CannedResponseInterceptor() { - URLRequest::UnregisterRequestInterceptor(this); + net::URLRequest::UnregisterRequestInterceptor(this); } private: - // URLRequest::Interceptor overrides. - virtual URLRequestJob* MaybeIntercept(URLRequest* request) { + // net::URLRequest::Interceptor overrides. + virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request) { if (request->url().GetOrigin() == service_url_.GetOrigin() && request->url().path() == service_url_.path()) { return new URLRequestTestJob(request, diff --git a/chrome/browser/policy/device_token_fetcher.cc b/chrome/browser/policy/device_token_fetcher.cc index 8f42544..678c90f 100644 --- a/chrome/browser/policy/device_token_fetcher.cc +++ b/chrome/browser/policy/device_token_fetcher.cc @@ -8,11 +8,11 @@ #include "base/path_service.h" #include "base/singleton.h" #include "base/string_util.h" -#include "chrome/browser/guid.h" #include "chrome/browser/net/gaia/token_service.h" #include "chrome/browser/policy/proto/device_management_local.pb.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/guid.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/common/notification_details.h" #include "chrome/common/notification_service.h" @@ -57,6 +57,31 @@ namespace policy { namespace em = enterprise_management; +DeviceTokenFetcher::ObserverRegistrar::ObserverRegistrar() {} + +DeviceTokenFetcher::ObserverRegistrar::~ObserverRegistrar() { + RemoveAll(); +} + +void DeviceTokenFetcher::ObserverRegistrar::Init( + DeviceTokenFetcher* token_fetcher) { + token_fetcher_ = token_fetcher; +} + +void DeviceTokenFetcher::ObserverRegistrar::AddObserver( + DeviceTokenFetcher::Observer* observer) { + observers_.push_back(observer); + token_fetcher_->AddObserver(observer); +} + +void DeviceTokenFetcher::ObserverRegistrar::RemoveAll() { + for (std::vector<DeviceTokenFetcher::Observer*>::iterator it = + observers_.begin(); it != observers_.end(); ++it) { + token_fetcher_->RemoveObserver(*it); + } + observers_.clear(); +} + DeviceTokenFetcher::DeviceTokenFetcher( DeviceManagementBackend* backend, Profile* profile, @@ -88,6 +113,8 @@ DeviceTokenFetcher::DeviceTokenFetcher( #endif } +DeviceTokenFetcher::~DeviceTokenFetcher() {} + void DeviceTokenFetcher::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { diff --git a/chrome/browser/policy/device_token_fetcher.h b/chrome/browser/policy/device_token_fetcher.h index 9b991de..c36af5b 100644 --- a/chrome/browser/policy/device_token_fetcher.h +++ b/chrome/browser/policy/device_token_fetcher.h @@ -43,23 +43,12 @@ class DeviceTokenFetcher class ObserverRegistrar { public: - void Init(DeviceTokenFetcher* token_fetcher) { - token_fetcher_ = token_fetcher; - } - ~ObserverRegistrar() { - RemoveAll(); - } - void AddObserver(DeviceTokenFetcher::Observer* observer) { - observers_.push_back(observer); - token_fetcher_->AddObserver(observer); - } - void RemoveAll() { - for (std::vector<DeviceTokenFetcher::Observer*>::iterator it = - observers_.begin(); it != observers_.end(); ++it) { - token_fetcher_->RemoveObserver(*it); - } - observers_.clear(); - } + ObserverRegistrar(); + ~ObserverRegistrar(); + + void Init(DeviceTokenFetcher* token_fetcher); + void AddObserver(DeviceTokenFetcher::Observer* observer); + void RemoveAll(); private: DeviceTokenFetcher* token_fetcher_; std::vector<DeviceTokenFetcher::Observer*> observers_; @@ -71,7 +60,7 @@ class DeviceTokenFetcher DeviceTokenFetcher(DeviceManagementBackend* backend, Profile* profile, const FilePath& token_path); - virtual ~DeviceTokenFetcher() {} + virtual ~DeviceTokenFetcher(); // NotificationObserver method overrides: virtual void Observe(NotificationType type, diff --git a/chrome/browser/policy/device_token_fetcher_unittest.cc b/chrome/browser/policy/device_token_fetcher_unittest.cc index e8c2c92..f4a7e23 100644 --- a/chrome/browser/policy/device_token_fetcher_unittest.cc +++ b/chrome/browser/policy/device_token_fetcher_unittest.cc @@ -12,7 +12,6 @@ #include "chrome/browser/policy/device_token_fetcher.h" #include "chrome/browser/policy/mock_device_management_backend.h" #include "chrome/common/net/gaia/gaia_constants.h" -#include "chrome/common/notification_service.h" #include "chrome/test/testing_device_token_fetcher.h" #include "chrome/test/testing_profile.h" #include "testing/gmock/include/gmock/gmock.h" diff --git a/chrome/browser/policy/dummy_configuration_policy_provider.cc b/chrome/browser/policy/dummy_configuration_policy_provider.cc new file mode 100644 index 0000000..9a8f491 --- /dev/null +++ b/chrome/browser/policy/dummy_configuration_policy_provider.cc @@ -0,0 +1,22 @@ +// 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/dummy_configuration_policy_provider.h" + +namespace policy { + +DummyConfigurationPolicyProvider::DummyConfigurationPolicyProvider( + const PolicyDefinitionList* policy_list) + : ConfigurationPolicyProvider(policy_list) { +} + +DummyConfigurationPolicyProvider::~DummyConfigurationPolicyProvider() { +} + +bool DummyConfigurationPolicyProvider::Provide( + ConfigurationPolicyStoreInterface* store) { + return true; +} + +} // namespace policy diff --git a/chrome/browser/policy/dummy_configuration_policy_provider.h b/chrome/browser/policy/dummy_configuration_policy_provider.h index 2c519cb..22ca152 100644 --- a/chrome/browser/policy/dummy_configuration_policy_provider.h +++ b/chrome/browser/policy/dummy_configuration_policy_provider.h @@ -6,24 +6,26 @@ #define CHROME_BROWSER_POLICY_DUMMY_CONFIGURATION_POLICY_PROVIDER_H_ #pragma once -#include "chrome/browser/policy/configuration_policy_store_interface.h" #include "chrome/browser/policy/configuration_policy_provider.h" namespace policy { +class ConfigurationPolicyStoreInterface; + class DummyConfigurationPolicyProvider : public ConfigurationPolicyProvider { public: explicit DummyConfigurationPolicyProvider( - const PolicyDefinitionList* policy_list) - : ConfigurationPolicyProvider(policy_list) { - } - virtual ~DummyConfigurationPolicyProvider() {} + const PolicyDefinitionList* policy_list); + virtual ~DummyConfigurationPolicyProvider(); - virtual bool Provide(ConfigurationPolicyStoreInterface* store) { - return true; - } + virtual bool Provide(ConfigurationPolicyStoreInterface* store); private: + // ConfigurationPolicyProvider overrides: + virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) {} + virtual void RemoveObserver( + ConfigurationPolicyProvider::Observer* observer) {} + DISALLOW_COPY_AND_ASSIGN(DummyConfigurationPolicyProvider); }; diff --git a/chrome/browser/policy/file_based_policy_loader.cc b/chrome/browser/policy/file_based_policy_loader.cc new file mode 100644 index 0000000..cc89d13 --- /dev/null +++ b/chrome/browser/policy/file_based_policy_loader.cc @@ -0,0 +1,144 @@ +// 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/file_based_policy_loader.h" + +namespace { + +// Amount of time we wait for the files on disk to settle before trying to load +// them. This alleviates the problem of reading partially written files and +// makes it possible to batch quasi-simultaneous changes. +const int kSettleIntervalSeconds = 5; + +// The time interval for rechecking policy. This is our fallback in case the +// delegate never reports a change to the ReloadObserver. +const int kReloadIntervalMinutes = 15; + +} // namespace + +namespace policy { + +FileBasedPolicyLoader::FileBasedPolicyLoader( + FileBasedPolicyProvider::ProviderDelegate* provider_delegate) + : AsynchronousPolicyLoader(provider_delegate, + kReloadIntervalMinutes), + config_file_path_(provider_delegate->config_file_path()), + settle_interval_(base::TimeDelta::FromSeconds(kSettleIntervalSeconds)) { +} + +FileBasedPolicyLoader::~FileBasedPolicyLoader() {} + +class FileBasedPolicyWatcherDelegate : public FilePathWatcher::Delegate { + public: + explicit FileBasedPolicyWatcherDelegate( + scoped_refptr<FileBasedPolicyLoader> loader) + : loader_(loader) {} + virtual ~FileBasedPolicyWatcherDelegate() {} + + // FilePathWatcher::Delegate implementation: + void OnFilePathChanged(const FilePath& path) { + loader_->OnFilePathChanged(path); + } + + void OnError() { + loader_->OnError(); + } + + private: + scoped_refptr<FileBasedPolicyLoader> loader_; + DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyWatcherDelegate); +}; + +void FileBasedPolicyLoader::OnFilePathChanged( + const FilePath& path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + Reload(); +} + +void FileBasedPolicyLoader::OnError() { + LOG(ERROR) << "FilePathWatcher on " << config_file_path().value() + << " failed."; +} + +void FileBasedPolicyLoader::Reload() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + if (!delegate()) + return; + + // Check the directory time in order to see whether a reload is required. + base::TimeDelta delay; + base::Time now = base::Time::Now(); + if (!IsSafeToReloadPolicy(now, &delay)) { + ScheduleReloadTask(delay); + return; + } + + // Load the policy definitions. + scoped_ptr<DictionaryValue> new_policy(delegate()->Load()); + + // Check again in case the directory has changed while reading it. + if (!IsSafeToReloadPolicy(now, &delay)) { + ScheduleReloadTask(delay); + return; + } + + PostUpdatePolicyTask(new_policy.release()); + + ScheduleFallbackReloadTask(); +} + +void FileBasedPolicyLoader::InitOnFileThread() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + watcher_.reset(new FilePathWatcher); + if (!config_file_path().empty() && + !watcher_->Watch(config_file_path(), + new FileBasedPolicyWatcherDelegate(this))) { + OnError(); + } + + // There might have been changes to the directory in the time between + // construction of the loader and initialization of the watcher. Call reload + // to detect if that is the case. + Reload(); + + ScheduleFallbackReloadTask(); +} + +void FileBasedPolicyLoader::StopOnFileThread() { + watcher_.reset(); + AsynchronousPolicyLoader::StopOnFileThread(); +} + +bool FileBasedPolicyLoader::IsSafeToReloadPolicy( + const base::Time& now, + base::TimeDelta* delay) { + DCHECK(delay); + + // A null modification time indicates there's no data. + FileBasedPolicyProvider::ProviderDelegate* provider_delegate = + static_cast<FileBasedPolicyProvider::ProviderDelegate*>(delegate()); + base::Time last_modification(provider_delegate->GetLastModification()); + if (last_modification.is_null()) + return true; + + // If there was a change since the last recorded modification, wait some more. + if (last_modification != last_modification_file_) { + last_modification_file_ = last_modification; + last_modification_clock_ = now; + *delay = settle_interval_; + return false; + } + + // Check whether the settle interval has elapsed. + base::TimeDelta age = now - last_modification_clock_; + if (age < settle_interval_) { + *delay = settle_interval_ - age; + return false; + } + + return true; +} + +} // namespace policy diff --git a/chrome/browser/policy/file_based_policy_loader.h b/chrome/browser/policy/file_based_policy_loader.h new file mode 100644 index 0000000..97c3198 --- /dev/null +++ b/chrome/browser/policy/file_based_policy_loader.h @@ -0,0 +1,78 @@ +// 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. + +#ifndef CHROME_BROWSER_POLICY_FILE_BASED_POLICY_LOADER_H_ +#define CHROME_BROWSER_POLICY_FILE_BASED_POLICY_LOADER_H_ +#pragma once + +#include "chrome/browser/file_path_watcher/file_path_watcher.h" +#include "chrome/browser/policy/asynchronous_policy_loader.h" +#include "chrome/browser/policy/file_based_policy_provider.h" + +namespace policy { + +// A customized asynchronous policy loader that handles loading policy from a +// file using a FilePathWatcher. The loader creates a fallback task to load +// policy periodically in case the watcher fails and retries policy loads when +// the watched file is in flux. +class FileBasedPolicyLoader : public AsynchronousPolicyLoader { + public: + FileBasedPolicyLoader( + FileBasedPolicyProvider::ProviderDelegate* provider_delegate); + + // AsynchronousPolicyLoader overrides: + virtual void Reload(); + + void OnFilePathChanged(const FilePath& path); + void OnError(); + + protected: + // FileBasedPolicyLoader objects should only be deleted by + // RefCountedThreadSafe. + friend class base::RefCountedThreadSafe<AsynchronousPolicyLoader>; + virtual ~FileBasedPolicyLoader(); + + const FilePath& config_file_path() { return config_file_path_; } + + // AsynchronousPolicyLoader overrides: + + // Creates the file path watcher and configures it to watch + // |config_file_path_|. Must be called on the file thread. + virtual void InitOnFileThread(); + virtual void StopOnFileThread(); + + private: + // Checks whether policy information is safe to read. If not, returns false + // and then delays until it is considered safe to reload in |delay|. + // Must be called on the file thread. + bool IsSafeToReloadPolicy(const base::Time& now, base::TimeDelta* delay); + + // The path at which we look for configuration files. + const FilePath config_file_path_; + + // Managed with a scoped_ptr rather than being declared as an inline member to + // decouple the watcher's life cycle from the loader's. This decoupling makes + // it possible to destroy the watcher before the loader's destructor is called + // (e.g. during Stop), since |watcher_| internally holds a reference to the + // loader and keeps it alive. + scoped_ptr<FilePathWatcher> watcher_; + + // Settle interval. + const base::TimeDelta settle_interval_; + + // Records last known modification timestamp of |config_file_path_|. + base::Time last_modification_file_; + + // The wall clock time at which the last modification timestamp was + // recorded. It's better to not assume the file notification time and the + // wall clock times come from the same source, just in case there is some + // non-local filesystem involved. + base::Time last_modification_clock_; + + DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyLoader); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_FILE_BASED_POLICY_LOADER_H_ diff --git a/chrome/browser/policy/file_based_policy_provider.cc b/chrome/browser/policy/file_based_policy_provider.cc index 578277d..488f19f 100644 --- a/chrome/browser/policy/file_based_policy_provider.cc +++ b/chrome/browser/policy/file_based_policy_provider.cc @@ -4,241 +4,21 @@ #include "chrome/browser/policy/file_based_policy_provider.h" -#include <set> - -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/task.h" -#include "base/utf_string_conversions.h" -#include "base/values.h" -#include "chrome/browser/browser_thread.h" -#include "chrome/common/json_value_serializer.h" +#include "chrome/browser/policy/file_based_policy_loader.h" namespace policy { -// Amount of time we wait for the files on disk to settle before trying to load -// it. This alleviates the problem of reading partially written files and allows -// to batch quasi-simultaneous changes. -const int kSettleIntervalSeconds = 5; - -// The time interval for rechecking policy. This is our fallback in case the -// file path watch fails or doesn't report a change. -const int kReloadIntervalMinutes = 15; - -// FileBasedPolicyProvider implementation: +FileBasedPolicyProvider::ProviderDelegate::ProviderDelegate( + const FilePath& config_file_path) + : config_file_path_(config_file_path) {} -FileBasedPolicyProvider::Delegate::~Delegate() { -} - -FileBasedPolicyProvider::Delegate::Delegate(const FilePath& config_file_path) - : config_file_path_(config_file_path) { -} +FileBasedPolicyProvider::ProviderDelegate::~ProviderDelegate() {} FileBasedPolicyProvider::FileBasedPolicyProvider( const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list, - FileBasedPolicyProvider::Delegate* delegate) - : ConfigurationPolicyProvider(policy_list) { - loader_ = new FileBasedPolicyLoader(AsWeakPtr(), - delegate, - kSettleIntervalSeconds, - kReloadIntervalMinutes); - watcher_ = new FileBasedPolicyWatcher; - watcher_->Init(loader_.get()); -} - -FileBasedPolicyProvider::~FileBasedPolicyProvider() { - loader_->Stop(); -} - -bool FileBasedPolicyProvider::Provide( - ConfigurationPolicyStoreInterface* store) { - scoped_ptr<DictionaryValue> policy(loader_->GetPolicy()); - DCHECK(policy.get()); - DecodePolicyValueTree(policy.get(), store); - return true; -} - -// FileBasedPolicyLoader implementation: - -FileBasedPolicyLoader::FileBasedPolicyLoader( - base::WeakPtr<ConfigurationPolicyProvider> provider, - FileBasedPolicyProvider::Delegate* delegate, - int settle_interval_seconds, - int reload_interval_minutes) - : delegate_(delegate), - provider_(provider), - origin_loop_(MessageLoop::current()), - reload_task_(NULL), - settle_interval_seconds_(settle_interval_seconds), - reload_interval_minutes_(reload_interval_minutes) { - // Force an initial load, so GetPolicy() works. - policy_.reset(delegate_->Load()); - DCHECK(policy_.get()); -} - -void FileBasedPolicyLoader::Stop() { - if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { - BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(this, &FileBasedPolicyLoader::Stop)); - return; - } - - if (reload_task_) { - reload_task_->Cancel(); - reload_task_ = NULL; - } -} - -void FileBasedPolicyLoader::Reload() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - // Check the directory time in order to see whether a reload is required. - base::TimeDelta delay; - base::Time now = base::Time::Now(); - if (!IsSafeToReloadPolicy(now, &delay)) { - ScheduleReloadTask(delay); - return; - } - - // Load the policy definitions. - scoped_ptr<DictionaryValue> new_policy(delegate_->Load()); - - // Check again in case the directory has changed while reading it. - if (!IsSafeToReloadPolicy(now, &delay)) { - ScheduleReloadTask(delay); - return; - } - - // Replace policy definition. - bool changed = false; - { - AutoLock lock(lock_); - changed = !policy_->Equals(new_policy.get()); - policy_.reset(new_policy.release()); - } - - // There's a change, report it! - if (changed) { - VLOG(0) << "Policy reload from " << config_file_path().value() - << " succeeded."; - origin_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &FileBasedPolicyLoader::NotifyPolicyChanged)); - } - - // As a safeguard in case the file watcher fails, schedule a reload task - // that'll make us recheck after a reasonable interval. - ScheduleReloadTask(base::TimeDelta::FromMinutes(reload_interval_minutes_)); -} - -DictionaryValue* FileBasedPolicyLoader::GetPolicy() { - AutoLock lock(lock_); - return static_cast<DictionaryValue*>(policy_->DeepCopy()); -} - -void FileBasedPolicyLoader::OnFilePathChanged(const FilePath& path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - Reload(); -} - -void FileBasedPolicyLoader::OnError() { - LOG(ERROR) << "FilePathWatcher on " << config_file_path().value() - << " failed."; -} - -FileBasedPolicyLoader::~FileBasedPolicyLoader() { -} - -bool FileBasedPolicyLoader::IsSafeToReloadPolicy(const base::Time& now, - base::TimeDelta* delay) { - DCHECK(delay); - - // A null modification time indicates there's no data. - base::Time last_modification(delegate_->GetLastModification()); - if (last_modification.is_null()) - return true; - - // If there was a change since the last recorded modification, wait some more. - base::TimeDelta settleInterval( - base::TimeDelta::FromSeconds(settle_interval_seconds_)); - if (last_modification != last_modification_file_) { - last_modification_file_ = last_modification; - last_modification_clock_ = now; - *delay = settleInterval; - return false; - } - - // Check whether the settle interval has elapsed. - base::TimeDelta age = now - last_modification_clock_; - if (age < settleInterval) { - *delay = settleInterval - age; - return false; - } - - return true; -} - -void FileBasedPolicyLoader::ScheduleReloadTask(const base::TimeDelta& delay) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - if (reload_task_) - reload_task_->Cancel(); - - reload_task_ = - NewRunnableMethod(this, &FileBasedPolicyLoader::ReloadFromTask); - BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_, - delay.InMilliseconds()); -} - -void FileBasedPolicyLoader::NotifyPolicyChanged() { - DCHECK_EQ(origin_loop_, MessageLoop::current()); - if (provider_) - provider_->NotifyStoreOfPolicyChange(); -} - -void FileBasedPolicyLoader::ReloadFromTask() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - // Drop the reference to the reload task, since the task might be the only - // referer that keeps us alive, so we should not Cancel() it. - reload_task_ = NULL; - - Reload(); -} - -// FileBasedPolicyWatcher implementation: - -FileBasedPolicyWatcher::FileBasedPolicyWatcher() { -} - -void FileBasedPolicyWatcher::Init(FileBasedPolicyLoader* loader) { - // Initialization can happen early when the file thread is not yet available. - // So post a task to ourselves on the UI thread which will run after threading - // is up and schedule watch initialization on the file thread. - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - NewRunnableMethod(this, - &FileBasedPolicyWatcher::InitWatcher, - scoped_refptr<FileBasedPolicyLoader>(loader))); -} - -FileBasedPolicyWatcher::~FileBasedPolicyWatcher() { -} - -void FileBasedPolicyWatcher::InitWatcher( - const scoped_refptr<FileBasedPolicyLoader>& loader) { - if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { - BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(this, &FileBasedPolicyWatcher::InitWatcher, loader)); - return; - } - - if (!loader->config_file_path().empty() && - !watcher_.Watch(loader->config_file_path(), loader.get())) - loader->OnError(); - - // There might have been changes to the directory in the time between - // construction of the loader and initialization of the watcher. Call reload - // to detect if that is the case. - loader->Reload(); -} + FileBasedPolicyProvider::ProviderDelegate* delegate) + : AsynchronousPolicyProvider( + policy_list, + new FileBasedPolicyLoader(delegate)) {} } // namespace policy diff --git a/chrome/browser/policy/file_based_policy_provider.h b/chrome/browser/policy/file_based_policy_provider.h index a4e989d..c94e1d4 100644 --- a/chrome/browser/policy/file_based_policy_provider.h +++ b/chrome/browser/policy/file_based_policy_provider.h @@ -6,39 +6,25 @@ #define CHROME_BROWSER_POLICY_FILE_BASED_POLICY_PROVIDER_H_ #pragma once -#include "base/basictypes.h" #include "base/file_path.h" -#include "base/lock.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" #include "base/time.h" -#include "base/weak_ptr.h" -#include "chrome/browser/file_path_watcher.h" -#include "chrome/browser/policy/configuration_policy_provider.h" - -class CancelableTask; -class DictionaryValue; -class MessageLoop; +#include "chrome/browser/policy/asynchronous_policy_provider.h" namespace policy { -class FileBasedPolicyLoader; -class FileBasedPolicyWatcher; - // File based policy provider that coordinates watching and reloading policy // information from the configuration path. Actual logic for loading policy // information is handled by a delegate passed at construction time. -class FileBasedPolicyProvider - : public ConfigurationPolicyProvider, - public base::SupportsWeakPtr<FileBasedPolicyProvider> { +class FileBasedPolicyProvider : public AsynchronousPolicyProvider { public: + // Delegate interface for actual policy loading from the system. - class Delegate { + class ProviderDelegate : public AsynchronousPolicyProvider::Delegate { public: - virtual ~Delegate(); + explicit ProviderDelegate(const FilePath& config_file_path); + virtual ~ProviderDelegate(); - // Loads the policy information. Ownership of the return value is - // transferred to the caller. + // AsynchronousPolicyProvider::Delegate implementation: virtual DictionaryValue* Load() = 0; // Gets the last modification timestamp for the policy information from the @@ -48,152 +34,21 @@ class FileBasedPolicyProvider const FilePath& config_file_path() { return config_file_path_; } - protected: - explicit Delegate(const FilePath& config_file_path); - private: - // The path at which we look for configuration files. const FilePath config_file_path_; - DISALLOW_COPY_AND_ASSIGN(Delegate); + DISALLOW_COPY_AND_ASSIGN(ProviderDelegate); }; // Assumes ownership of |delegate|. FileBasedPolicyProvider(const PolicyDefinitionList* policy_list, - Delegate* delegate); - virtual ~FileBasedPolicyProvider(); - - // ConfigurationPolicyProvider implementation. - virtual bool Provide(ConfigurationPolicyStoreInterface* store); + ProviderDelegate* delegate); + virtual ~FileBasedPolicyProvider() {} private: - // Watches for changes to the configuration directory. - scoped_refptr<FileBasedPolicyWatcher> watcher_; - - // The loader object we use internally. - scoped_refptr<FileBasedPolicyLoader> loader_; - DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyProvider); }; -// FilePathWatcher delegate implementation that handles change notifications for -// the configuration file or directory. It keeps the authorative version of the -// currently effective policy dictionary and updates it as appropriate. The -// actual loading logic is handled by a delegate. -class FileBasedPolicyLoader : public FilePathWatcher::Delegate { - public: - // Creates a new loader that'll load its data from |config_file_path|. - // Assumes ownership of |delegate|, which provides the actual loading logic. - // The parameters |settle_interval_seconds| and |reload_interval_minutes| - // specify the time to wait before reading the file contents after a change - // and the period for checking |config_file_path| for changes, respectively. - FileBasedPolicyLoader(base::WeakPtr<ConfigurationPolicyProvider> provider, - FileBasedPolicyProvider::Delegate* delegate, - int settle_interval_seconds, - int reload_interval_minutes); - - // Stops any pending reload tasks. - void Stop(); - - // Reloads the policies and sends out a notification, if appropriate. Must be - // called on the file thread. - void Reload(); - - // Gets the current dictionary value object. Ownership of the returned value - // is transferred to the caller. - DictionaryValue* GetPolicy(); - - const FilePath& config_file_path() { return delegate_->config_file_path(); } - - // FilePathWatcher::Delegate implementation: - void OnFilePathChanged(const FilePath& path); - void OnError(); - - private: - // FileBasedPolicyLoader objects should only be deleted by - // RefCountedThreadSafe. - friend class base::RefCountedThreadSafe<FileBasedPolicyLoader>; - virtual ~FileBasedPolicyLoader(); - - // Checks whether reading policy information is safe to do. If not, returns - // false and the delay until it is considered safe to reload in |delay|. - bool IsSafeToReloadPolicy(const base::Time& now, base::TimeDelta* delay); - - // Schedules a reload task to run when |delay| expires. Must be called on the - // file thread. - void ScheduleReloadTask(const base::TimeDelta& delay); - - // Notifies the policy provider to send out a policy changed notification. - // Must be called on |origin_loop_|. - void NotifyPolicyChanged(); - - // Invoked from the reload task on the file thread. - void ReloadFromTask(); - - // The delegate. - scoped_ptr<FileBasedPolicyProvider::Delegate> delegate_; - - // The provider this loader is associated with. Access only on the thread that - // called the constructor. See |origin_loop_| below. - base::WeakPtr<ConfigurationPolicyProvider> provider_; - - // The message loop on which this object was constructed and |provider_| - // received on. Recorded so we can call back into the non thread safe provider - // to fire the notification. - MessageLoop* origin_loop_; - - // Records last known modification timestamp of |config_file_path_|. - base::Time last_modification_file_; - - // The wall clock time at which the last modification timestamp was recorded. - // It's better to not assume the file notification time and the wall clock - // times come from the same source, just in case there is some non-local - // filesystem involved. - base::Time last_modification_clock_; - - // Protects |policy_|. - Lock lock_; - - // The current policy definition. - scoped_ptr<DictionaryValue> policy_; - - // The reload task. Access only on the file thread. Holds a reference to the - // currently posted task, so we can cancel and repost it if necessary. - CancelableTask* reload_task_; - - // Settle and reload intervals. - const int settle_interval_seconds_; - const int reload_interval_minutes_; - - DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyLoader); -}; - -// Wraps a FilePathWatcher for the configuration path and takes care of -// initializing the watcher object on the file thread. -class FileBasedPolicyWatcher - : public base::RefCountedThreadSafe<FileBasedPolicyWatcher> { - public: - FileBasedPolicyWatcher(); - - // Runs initialization. This is in a separate method since we need to post a - // task (which cannot be done from the constructor). - void Init(FileBasedPolicyLoader* loader); - - private: - // FileBasedPolicyWatcher objects should only be deleted by - // RefCountedThreadSafe. - friend class base::RefCountedThreadSafe<FileBasedPolicyWatcher>; - virtual ~FileBasedPolicyWatcher(); - - // Actually sets up the watch with the FilePathWatcher code. - void InitWatcher(const scoped_refptr<FileBasedPolicyLoader>& loader); - - // Wrapped watcher that takes care of the actual watching. - FilePathWatcher watcher_; - - DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyWatcher); -}; - } // namespace policy #endif // CHROME_BROWSER_POLICY_FILE_BASED_POLICY_PROVIDER_H_ diff --git a/chrome/browser/policy/file_based_policy_provider_unittest.cc b/chrome/browser/policy/file_based_policy_provider_unittest.cc index c78c586..1bb2185 100644 --- a/chrome/browser/policy/file_based_policy_provider_unittest.cc +++ b/chrome/browser/policy/file_based_policy_provider_unittest.cc @@ -2,130 +2,80 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/policy/asynchronous_policy_loader.h" +#include "chrome/browser/policy/asynchronous_policy_test_base.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" +#include "chrome/browser/policy/configuration_policy_store_interface.h" #include "chrome/browser/policy/file_based_policy_provider.h" +#include "chrome/common/policy_constants.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -using testing::Mock; +using testing::_; +using testing::InSequence; +using testing::Return; namespace policy { -// Shorter reload intervals for testing FileBasedPolicyLoader. -const int kSettleIntervalSecondsForTesting = 0; -const int kReloadIntervalMinutesForTesting = 1; - -// A delegate for testing that can feed arbitrary information to the loader. -class TestDelegate : public FileBasedPolicyProvider::Delegate { - public: - TestDelegate() - : FileBasedPolicyProvider::Delegate(FilePath(FILE_PATH_LITERAL("fake"))) { - } - - // FileBasedPolicyProvider::Delegate implementation: - virtual DictionaryValue* Load() { - return static_cast<DictionaryValue*>(dict_.DeepCopy()); - } - - virtual base::Time GetLastModification() { - return last_modification_; - } - - DictionaryValue* dict() { return &dict_; } - void set_last_modification(const base::Time& last_modification) { - last_modification_ = last_modification; - } - - private: - DictionaryValue dict_; - base::Time last_modification_; -}; - -// A mock provider that allows us to capture reload notifications. -class MockPolicyProvider : public ConfigurationPolicyProvider, - public base::SupportsWeakPtr<MockPolicyProvider> { +class FileBasedPolicyProviderDelegateMock + : public FileBasedPolicyProvider::ProviderDelegate { public: - explicit MockPolicyProvider() - : ConfigurationPolicyProvider( - ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList()) { - } - - virtual bool Provide(ConfigurationPolicyStoreInterface* store) { - return true; - } - - MOCK_METHOD0(NotifyStoreOfPolicyChange, void()); + FileBasedPolicyProviderDelegateMock() + : FileBasedPolicyProvider::ProviderDelegate(FilePath()) {} + MOCK_METHOD0(Load, DictionaryValue*()); + MOCK_METHOD0(GetLastModification, base::Time()); }; -class FileBasedPolicyLoaderTest : public testing::Test { - protected: - FileBasedPolicyLoaderTest() - : ui_thread_(BrowserThread::UI, &loop_), - file_thread_(BrowserThread::FILE, &loop_) {} - - virtual void TearDown() { - loop_.RunAllPending(); - } - - MessageLoop loop_; - - private: - BrowserThread ui_thread_; - BrowserThread file_thread_; -}; - -TEST_F(FileBasedPolicyLoaderTest, BasicLoad) { - TestDelegate* test_delegate = new TestDelegate; - test_delegate->dict()->SetString("HomepageLocation", "http://www.google.com"); - - scoped_refptr<FileBasedPolicyLoader> loader( - new FileBasedPolicyLoader(base::WeakPtr<FileBasedPolicyProvider>(), - test_delegate, - kSettleIntervalSecondsForTesting, - kReloadIntervalMinutesForTesting)); - scoped_ptr<DictionaryValue> policy(loader->GetPolicy()); - EXPECT_TRUE(policy.get()); - EXPECT_EQ(1U, policy->size()); - - std::string str_value; - EXPECT_TRUE(policy->GetString("HomepageLocation", &str_value)); - EXPECT_EQ("http://www.google.com", str_value); - - loader->Stop(); +TEST_F(AsynchronousPolicyTestBase, ProviderInit) { + base::Time last_modified; + FileBasedPolicyProviderDelegateMock* provider_delegate = + new FileBasedPolicyProviderDelegateMock(); + EXPECT_CALL(*provider_delegate, GetLastModification()).WillRepeatedly( + Return(last_modified)); + InSequence s; + EXPECT_CALL(*provider_delegate, Load()).WillOnce(Return( + new DictionaryValue)); + DictionaryValue* policies = new DictionaryValue(); + policies->SetBoolean(policy::key::kSyncDisabled, true); + // A second call to Load gets triggered during the provider's construction + // when the file watcher is initialized, since this file may have changed + // between the initial load and creating watcher. + EXPECT_CALL(*provider_delegate, Load()).WillOnce(Return(policies)); + FileBasedPolicyProvider provider( + ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), + provider_delegate); + loop_.RunAllPending(); + EXPECT_CALL(*store_, Apply(policy::kPolicySyncDisabled, _)).Times(1); + provider.Provide(store_.get()); } -TEST_F(FileBasedPolicyLoaderTest, TestRefresh) { - MockPolicyProvider provider; - TestDelegate* test_delegate = new TestDelegate; - - scoped_refptr<FileBasedPolicyLoader> loader( - new FileBasedPolicyLoader(provider.AsWeakPtr(), - test_delegate, - kSettleIntervalSecondsForTesting, - kReloadIntervalMinutesForTesting)); - scoped_ptr<DictionaryValue> policy(loader->GetPolicy()); - EXPECT_TRUE(policy.get()); - EXPECT_EQ(0U, policy->size()); - - test_delegate->dict()->SetString("HomepageLocation", "http://www.google.com"); - - EXPECT_CALL(provider, NotifyStoreOfPolicyChange()).Times(1); - loader->OnFilePathChanged(FilePath(FILE_PATH_LITERAL("fake"))); - - // Run the loop. The refresh should be handled immediately since the settle - // interval has been disabled. +TEST_F(AsynchronousPolicyTestBase, ProviderRefresh) { + base::Time last_modified; + FileBasedPolicyProviderDelegateMock* provider_delegate = + new FileBasedPolicyProviderDelegateMock(); + EXPECT_CALL(*provider_delegate, GetLastModification()).WillRepeatedly( + Return(last_modified)); + InSequence s; + EXPECT_CALL(*provider_delegate, Load()).WillOnce(Return( + new DictionaryValue)); + FileBasedPolicyProvider file_based_provider( + ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), + provider_delegate); + // A second call to Load gets triggered during the provider's construction + // when the file watcher is initialized, since this file may have changed + // between the initial load and creating watcher. + EXPECT_CALL(*provider_delegate, Load()).WillOnce(Return( + new DictionaryValue)); loop_.RunAllPending(); - Mock::VerifyAndClearExpectations(&provider); - - policy.reset(loader->GetPolicy()); - EXPECT_TRUE(policy.get()); - EXPECT_EQ(1U, policy->size()); - - std::string str_value; - EXPECT_TRUE(policy->GetString("HomepageLocation", &str_value)); - EXPECT_EQ("http://www.google.com", str_value); - - loader->Stop(); + // A third and final call to Load is made by the explicit Reload. This + // should be the one that provides the current policy. + DictionaryValue* policies = new DictionaryValue(); + policies->SetBoolean(policy::key::kSyncDisabled, true); + EXPECT_CALL(*provider_delegate, Load()).WillOnce(Return(policies)); + file_based_provider.loader()->Reload(); + loop_.RunAllPending(); + EXPECT_CALL(*store_, Apply(policy::kPolicySyncDisabled, _)).Times(1); + file_based_provider.Provide(store_.get()); } } // namespace policy diff --git a/chrome/browser/policy/managed_prefs_banner_base.cc b/chrome/browser/policy/managed_prefs_banner_base.cc index 1351da4..7c20a09 100644 --- a/chrome/browser/policy/managed_prefs_banner_base.cc +++ b/chrome/browser/policy/managed_prefs_banner_base.cc @@ -84,8 +84,7 @@ void ManagedPrefsBannerBase::Init(PrefService* local_state, #if defined(GOOGLE_CHROME_BUILD) AddLocalStatePref(prefs::kMetricsReportingEnabled); #endif - AddUserPref(prefs::kNoProxyServer); - AddUserPref(prefs::kProxyAutoDetect); + AddUserPref(prefs::kProxyMode); AddUserPref(prefs::kProxyServer); AddUserPref(prefs::kProxyPacUrl); AddUserPref(prefs::kProxyBypassList); diff --git a/chrome/browser/policy/managed_prefs_banner_base.h b/chrome/browser/policy/managed_prefs_banner_base.h index e087cb1..40b798e 100644 --- a/chrome/browser/policy/managed_prefs_banner_base.h +++ b/chrome/browser/policy/managed_prefs_banner_base.h @@ -8,7 +8,7 @@ #include "base/basictypes.h" #include "base/scoped_ptr.h" -#include "chrome/browser/options_window.h" +#include "chrome/browser/ui/options/options_window.h" #include "chrome/common/notification_observer.h" class PrefService; diff --git a/chrome/browser/policy/managed_prefs_banner_base_unittest.cc b/chrome/browser/policy/managed_prefs_banner_base_unittest.cc index 35425b1..3f2569d 100644 --- a/chrome/browser/policy/managed_prefs_banner_base_unittest.cc +++ b/chrome/browser/policy/managed_prefs_banner_base_unittest.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "chrome/browser/policy/managed_prefs_banner_base.h" -#include "chrome/browser/prefs/dummy_pref_store.h" #include "chrome/common/pref_names.h" #include "chrome/test/testing_pref_service.h" #include "testing/gmock/include/gmock/gmock.h" diff --git a/chrome/browser/policy/mock_configuration_policy_provider.cc b/chrome/browser/policy/mock_configuration_policy_provider.cc index 4f11497..a2566b0 100644 --- a/chrome/browser/policy/mock_configuration_policy_provider.cc +++ b/chrome/browser/policy/mock_configuration_policy_provider.cc @@ -4,13 +4,15 @@ #include "chrome/browser/policy/mock_configuration_policy_provider.h" +#include "base/stl_util-inl.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" namespace policy { MockConfigurationPolicyProvider::MockConfigurationPolicyProvider() : ConfigurationPolicyProvider( - ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList()) { + ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList()), + initialization_complete_(false) { } MockConfigurationPolicyProvider::~MockConfigurationPolicyProvider() { @@ -23,6 +25,20 @@ void MockConfigurationPolicyProvider::AddPolicy(ConfigurationPolicyType policy, delete 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); + } +} + +void MockConfigurationPolicyProvider::SetInitializationComplete( + bool initialization_complete) { + initialization_complete_ = initialization_complete; +} + bool MockConfigurationPolicyProvider::Provide( ConfigurationPolicyStoreInterface* store) { for (PolicyMap::const_iterator current = policy_map_.begin(); @@ -32,4 +48,8 @@ bool MockConfigurationPolicyProvider::Provide( return true; } +bool MockConfigurationPolicyProvider::IsInitializationComplete() const { + return initialization_complete_; +} + } diff --git a/chrome/browser/policy/mock_configuration_policy_provider.h b/chrome/browser/policy/mock_configuration_policy_provider.h index 8ba8a88..5620f81 100644 --- a/chrome/browser/policy/mock_configuration_policy_provider.h +++ b/chrome/browser/policy/mock_configuration_policy_provider.h @@ -9,8 +9,8 @@ #include <map> #include <utility> -#include "base/stl_util-inl.h" #include "chrome/browser/policy/configuration_policy_provider.h" +#include "testing/gmock/include/gmock/gmock.h" namespace policy { @@ -22,14 +22,24 @@ class MockConfigurationPolicyProvider : public ConfigurationPolicyProvider { virtual ~MockConfigurationPolicyProvider(); void AddPolicy(ConfigurationPolicyType policy, Value* value); + void RemovePolicy(ConfigurationPolicyType policy); + + void SetInitializationComplete(bool initialization_complete); // ConfigurationPolicyProvider method overrides. virtual bool Provide(ConfigurationPolicyStoreInterface* store); + virtual bool IsInitializationComplete() const; private: + // ConfigurationPolicyProvider overrides: + virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) {} + virtual void RemoveObserver( + ConfigurationPolicyProvider::Observer* observer) {} + typedef std::map<ConfigurationPolicyType, Value*> PolicyMap; PolicyMap policy_map_; + bool initialization_complete_; }; } // namespace policy diff --git a/chrome/browser/policy/profile_policy_context.cc b/chrome/browser/policy/profile_policy_context.cc index 0882ab4..c4b6e5b 100644 --- a/chrome/browser/policy/profile_policy_context.cc +++ b/chrome/browser/policy/profile_policy_context.cc @@ -7,7 +7,7 @@ #include "chrome/browser/policy/device_management_policy_provider.h" #include "chrome/browser/policy/device_management_service.h" #include "chrome/browser/policy/profile_policy_context.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_switches.h" namespace policy { |