diff options
author | jkummerow@chromium.org <jkummerow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-23 09:54:25 +0000 |
---|---|---|
committer | jkummerow@chromium.org <jkummerow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-23 09:54:25 +0000 |
commit | 985655a307077dc9385fa4ed00bed3b8a64a805a (patch) | |
tree | 44b6ef8af1970224f900cf4da7fca9a35d414526 /chrome | |
parent | d63c6fc43c28f3153b3c6b758796e7d15c44bdd0 (diff) | |
download | chromium_src-985655a307077dc9385fa4ed00bed3b8a64a805a.zip chromium_src-985655a307077dc9385fa4ed00bed3b8a64a805a.tar.gz chromium_src-985655a307077dc9385fa4ed00bed3b8a64a805a.tar.bz2 |
Device policy infrastructure
This continues the work of http://codereview.chromium.org/6312121/. Description of that CL:
This refactors the cloud policy-related code to support device policy
that gets associated with the whole browser session. Device policy
information will show up in g_browser_process->local_state(). Also,
start supporting recommended policy from the cloud.
BUG=chromium-os:11259, chromium-os:11257, chromium-os:11256
TEST=Enable device policy by passing --device-policy-cache-dir, claim a device and verify that policy gets downloaded.
Review URL: http://codereview.chromium.org/6520008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75732 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
51 files changed, 2582 insertions, 2222 deletions
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h index 5c7d33d..3dbd8e6 100644 --- a/chrome/browser/browser_process.h +++ b/chrome/browser/browser_process.h @@ -52,7 +52,7 @@ class PrintPreviewTabController; } namespace policy { -class ConfigurationPolicyProviderKeeper; +class BrowserPolicyConnector; } namespace ui { @@ -119,8 +119,7 @@ class BrowserProcess { // Returns the thread that is used for health check of all browser threads. virtual WatchDogThread* watchdog_thread() = 0; - virtual policy::ConfigurationPolicyProviderKeeper* - configuration_policy_provider_keeper() = 0; + virtual policy::BrowserPolicyConnector* browser_policy_connector() = 0; virtual IconManager* icon_manager() = 0; diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 780169a..0984234 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -9,10 +9,10 @@ #include "base/command_line.h" #include "base/file_util.h" #include "base/path_service.h" +#include "base/synchronization/waitable_event.h" #include "base/task.h" #include "base/threading/thread.h" #include "base/threading/thread_restrictions.h" -#include "base/synchronization/waitable_event.h" #include "chrome/browser/automation/automation_provider_list.h" #include "chrome/browser/browser_child_process_host.h" #include "chrome/browser/browser_list.h" @@ -40,7 +40,7 @@ #include "chrome/browser/plugin_data_remover.h" #include "chrome/browser/plugin_service.h" #include "chrome/browser/plugin_updater.h" -#include "chrome/browser/policy/configuration_policy_provider_keeper.h" +#include "chrome/browser/policy/browser_policy_connector.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/printing/print_preview_tab_controller.h" @@ -55,13 +55,13 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/extensions/extension_resource.h" #include "chrome/common/extensions/extension_l10n_util.h" +#include "chrome/common/extensions/extension_resource.h" #include "chrome/common/json_pref_store.h" #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" -#include "chrome/common/url_constants.h" #include "chrome/common/switch_utils.h" +#include "chrome/common/url_constants.h" #include "chrome/installer/util/google_update_constants.h" #include "ipc/ipc_logging.h" #include "ui/base/clipboard/clipboard.h" @@ -104,7 +104,7 @@ BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line) created_icon_manager_(false), created_devtools_manager_(false), created_sidebar_manager_(false), - created_configuration_policy_provider_keeper_(false), + created_browser_policy_connector_(false), created_notification_ui_manager_(false), created_safe_browsing_detection_service_(false), module_ref_count_(0), @@ -189,9 +189,9 @@ BrowserProcessImpl::~BrowserProcessImpl() { resource_dispatcher_host()->Shutdown(); } - // The policy providers managed by |configuration_policy_provider_keeper_| - // need to shut down while the file thread is still alive. - configuration_policy_provider_keeper_.reset(); + // The policy providers managed by |browser_policy_connector_| need to shut + // down while the IO and FILE threads are still alive. + browser_policy_connector_.reset(); #if defined(USE_X11) // The IO thread must outlive the BACKGROUND_X11 thread. @@ -443,16 +443,14 @@ NotificationUIManager* BrowserProcessImpl::notification_ui_manager() { return notification_ui_manager_.get(); } -policy::ConfigurationPolicyProviderKeeper* - BrowserProcessImpl::configuration_policy_provider_keeper() { +policy::BrowserPolicyConnector* BrowserProcessImpl::browser_policy_connector() { DCHECK(CalledOnValidThread()); - if (!created_configuration_policy_provider_keeper_) { - DCHECK(configuration_policy_provider_keeper_.get() == NULL); - created_configuration_policy_provider_keeper_ = true; - configuration_policy_provider_keeper_.reset( - new policy::ConfigurationPolicyProviderKeeper()); + if (!created_browser_policy_connector_) { + DCHECK(browser_policy_connector_.get() == NULL); + created_browser_policy_connector_ = true; + browser_policy_connector_.reset(new policy::BrowserPolicyConnector()); } - return configuration_policy_provider_keeper_.get(); + return browser_policy_connector_.get(); } IconManager* BrowserProcessImpl::icon_manager() { diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h index a3e0a36..06e56b7 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h @@ -15,9 +15,9 @@ #include "base/basictypes.h" #include "base/message_loop.h" +#include "base/scoped_ptr.h" #include "base/threading/non_thread_safe.h" #include "base/timer.h" -#include "base/scoped_ptr.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_status_updater.h" #include "chrome/browser/prefs/pref_change_registrar.h" @@ -63,8 +63,7 @@ class BrowserProcessImpl : public BrowserProcess, virtual SidebarManager* sidebar_manager(); virtual ui::Clipboard* clipboard(); virtual NotificationUIManager* notification_ui_manager(); - virtual policy::ConfigurationPolicyProviderKeeper* - configuration_policy_provider_keeper(); + virtual policy::BrowserPolicyConnector* browser_policy_connector(); virtual IconManager* icon_manager(); virtual ThumbnailGenerator* GetThumbnailGenerator(); virtual AutomationProviderList* InitAutomationProviderList(); @@ -193,9 +192,8 @@ class BrowserProcessImpl : public BrowserProcess, bool created_sidebar_manager_; scoped_refptr<SidebarManager> sidebar_manager_; - bool created_configuration_policy_provider_keeper_; - scoped_ptr<policy::ConfigurationPolicyProviderKeeper> - configuration_policy_provider_keeper_; + bool created_browser_policy_connector_; + scoped_ptr<policy::BrowserPolicyConnector> browser_policy_connector_; scoped_refptr<printing::PrintPreviewTabController> print_preview_tab_controller_; diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc new file mode 100644 index 0000000..33c7c3e --- /dev/null +++ b/chrome/browser/policy/browser_policy_connector.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/browser_policy_connector.h" + +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/policy/cloud_policy_identity_strategy.h" +#include "chrome/browser/policy/cloud_policy_subsystem.h" +#include "chrome/browser/policy/configuration_policy_pref_store.h" +#include "chrome/browser/policy/configuration_policy_provider.h" +#include "chrome/browser/policy/dummy_configuration_policy_provider.h" +#include "chrome/browser/prefs/pref_service.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" +#include "chrome/common/pref_names.h" + +#if defined(OS_WIN) +#include "chrome/browser/policy/configuration_policy_provider_win.h" +#elif defined(OS_MACOSX) +#include "chrome/browser/policy/configuration_policy_provider_mac.h" +#elif defined(OS_POSIX) +#include "chrome/browser/policy/config_dir_policy_provider.h" +#endif + +#if defined(OS_CHROMEOS) +#include "chrome/browser/policy/device_policy_identity_strategy.h" +#endif + +namespace { + +const FilePath::CharType kDevicePolicyCacheFile[] = + FILE_PATH_LITERAL("Policy"); + +} // namespace + +namespace policy { + +BrowserPolicyConnector::BrowserPolicyConnector() { + managed_platform_provider_.reset(CreateManagedPlatformProvider()); + recommended_platform_provider_.reset(CreateRecommendedPlatformProvider()); + registrar_.Add(this, NotificationType::DEFAULT_REQUEST_CONTEXT_AVAILABLE, + NotificationService::AllSources()); + +#if defined(OS_CHROMEOS) + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kDevicePolicyCacheDir)) { + FilePath cache_dir(command_line->GetSwitchValuePath( + switches::kDevicePolicyCacheDir)); + + if (!file_util::CreateDirectory(cache_dir)) { + LOG(WARNING) << "Device policy cache directory " + << cache_dir.value() + << " is not accessible, skipping initialization."; + } else { + identity_strategy_.reset(new DevicePolicyIdentityStrategy()); + cloud_policy_subsystem_.reset( + new CloudPolicySubsystem(cache_dir.Append(kDevicePolicyCacheFile), + identity_strategy_.get())); + } + } +#endif +} + +BrowserPolicyConnector::BrowserPolicyConnector( + ConfigurationPolicyProvider* managed_platform_provider, + ConfigurationPolicyProvider* recommended_platform_provider) + : managed_platform_provider_(managed_platform_provider), + recommended_platform_provider_(recommended_platform_provider) {} + +BrowserPolicyConnector::~BrowserPolicyConnector() { + if (cloud_policy_subsystem_.get()) + cloud_policy_subsystem_->Shutdown(); + cloud_policy_subsystem_.reset(); + identity_strategy_.reset(); +} + +ConfigurationPolicyProvider* + BrowserPolicyConnector::GetManagedPlatformProvider() const { + return managed_platform_provider_.get(); +} + +ConfigurationPolicyProvider* + BrowserPolicyConnector::GetManagedCloudProvider() const { + if (cloud_policy_subsystem_.get()) + return cloud_policy_subsystem_->GetManagedPolicyProvider(); + + return NULL; +} + +ConfigurationPolicyProvider* + BrowserPolicyConnector::GetRecommendedPlatformProvider() const { + return recommended_platform_provider_.get(); +} + +ConfigurationPolicyProvider* + BrowserPolicyConnector::GetRecommendedCloudProvider() const { + if (cloud_policy_subsystem_.get()) + return cloud_policy_subsystem_->GetRecommendedPolicyProvider(); + + return NULL; +} + +ConfigurationPolicyProvider* + BrowserPolicyConnector::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* + BrowserPolicyConnector::CreateRecommendedPlatformProvider() { + 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 +} + +// static +void BrowserPolicyConnector::RegisterPrefs(PrefService* local_state) { + local_state->RegisterIntegerPref(prefs::kPolicyDevicePolicyRefreshRate, + kDefaultPolicyRefreshRateInMilliseconds); +} + +void BrowserPolicyConnector::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::DEFAULT_REQUEST_CONTEXT_AVAILABLE) { + Initialize(g_browser_process->local_state(), + Profile::GetDefaultRequestContext()); + } else { + NOTREACHED(); + } +} + +void BrowserPolicyConnector::Initialize( + PrefService* local_state, + URLRequestContextGetter* request_context) { + // TODO(jkummerow, mnissler): Move this out of the browser startup path. + DCHECK(local_state); + DCHECK(request_context); + if (cloud_policy_subsystem_.get()) { + cloud_policy_subsystem_->Initialize(local_state, + prefs::kPolicyDevicePolicyRefreshRate, + request_context); + } +} + +} // namespace diff --git a/chrome/browser/policy/browser_policy_connector.h b/chrome/browser/policy/browser_policy_connector.h new file mode 100644 index 0000000..17e8c14 --- /dev/null +++ b/chrome/browser/policy/browser_policy_connector.h @@ -0,0 +1,77 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_BROWSER_POLICY_CONNECTOR_H_ +#define CHROME_BROWSER_POLICY_BROWSER_POLICY_CONNECTOR_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" + +class PrefService; +class TestingBrowserProcess; +class TokenService; +class URLRequestContextGetter; + +namespace policy { + +class CloudPolicyIdentityStrategy; +class CloudPolicySubsystem; +class ConfigurationPolicyProvider; + +// Manages the lifecycle of browser-global policy infrastructure, such as the +// platform policy providers. +class BrowserPolicyConnector : public NotificationObserver { + public: + static const int kDefaultPolicyRefreshRateInMilliseconds = + 3 * 60 * 60 * 1000; // 3 hours. + + BrowserPolicyConnector(); + ~BrowserPolicyConnector(); + + ConfigurationPolicyProvider* GetManagedPlatformProvider() const; + ConfigurationPolicyProvider* GetManagedCloudProvider() const; + ConfigurationPolicyProvider* GetRecommendedPlatformProvider() const; + ConfigurationPolicyProvider* GetRecommendedCloudProvider() const; + + static void RegisterPrefs(PrefService* user_prefs); + + // NotificationObserver implementation: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + private: + friend class ::TestingBrowserProcess; + + static ConfigurationPolicyProvider* CreateManagedPlatformProvider(); + static ConfigurationPolicyProvider* CreateRecommendedPlatformProvider(); + + // Constructor for tests that allows tests to use fake platform policy + // providers instead of using the actual ones. + BrowserPolicyConnector( + ConfigurationPolicyProvider* managed_platform_provider, + ConfigurationPolicyProvider* recommended_platform_provider); + + // Activates the cloud policy subsystem. Called when the default request + // context is available. + void Initialize(PrefService* local_state, + URLRequestContextGetter* request_context); + + scoped_ptr<ConfigurationPolicyProvider> managed_platform_provider_; + scoped_ptr<ConfigurationPolicyProvider> recommended_platform_provider_; + + scoped_ptr<CloudPolicyIdentityStrategy> identity_strategy_; + scoped_ptr<CloudPolicySubsystem> cloud_policy_subsystem_; + + NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(BrowserPolicyConnector); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_BROWSER_POLICY_CONNECTOR_H_ diff --git a/chrome/browser/policy/cloud_policy_cache.cc b/chrome/browser/policy/cloud_policy_cache.cc index b81fb81..c7b96b8 100644 --- a/chrome/browser/policy/cloud_policy_cache.cc +++ b/chrome/browser/policy/cloud_policy_cache.cc @@ -11,8 +11,8 @@ #include "base/task.h" #include "base/values.h" #include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/proto/cloud_policy.pb.h" -#include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "chrome/browser/policy/proto/device_management_constants.h" #include "chrome/browser/policy/proto/device_management_local.pb.h" @@ -33,6 +33,51 @@ namespace policy { void DecodePolicy(const em::CloudPolicySettings& policy, PolicyMap* mandatory, PolicyMap* recommended); +// A thin ConfigurationPolicyProvider implementation sitting on top of +// CloudPolicyCache for hooking up with ConfigurationPolicyPrefStore. +class CloudPolicyCache::CloudPolicyProvider + : public ConfigurationPolicyProvider { + public: + CloudPolicyProvider(const PolicyDefinitionList* policy_list, + CloudPolicyCache* cache, + CloudPolicyCache::PolicyLevel level) + : ConfigurationPolicyProvider(policy_list), + cache_(cache), + level_(level) {} + virtual ~CloudPolicyProvider() {} + + virtual bool Provide(ConfigurationPolicyStoreInterface* store) { + if (!cache_->has_device_policy()) { + if (level_ == POLICY_LEVEL_MANDATORY) + ApplyPolicyMap(&cache_->mandatory_policy_, store); + else if (level_ == POLICY_LEVEL_RECOMMENDED) + ApplyPolicyMap(&cache_->recommended_policy_, store); + } else { + ApplyPolicyValueTree(cache_->device_policy_.get(), store); + } + return true; + } + + virtual bool IsInitializationComplete() const { + return cache_->initialization_complete_; + } + + virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) { + cache_->observer_list_.AddObserver(observer); + } + virtual void RemoveObserver(ConfigurationPolicyProvider::Observer* observer) { + cache_->observer_list_.RemoveObserver(observer); + } + + private: + // The underlying policy cache. + CloudPolicyCache* cache_; + // Policy level this provider will handle. + CloudPolicyCache::PolicyLevel level_; + + DISALLOW_COPY_AND_ASSIGN(CloudPolicyProvider); +}; + // Saves policy information to a file. class PersistPolicyTask : public Task { public: @@ -85,17 +130,30 @@ CloudPolicyCache::CloudPolicyCache( const FilePath& backing_file_path) : backing_file_path_(backing_file_path), device_policy_(new DictionaryValue), - fresh_policy_(false), + initialization_complete_(false), is_unmanaged_(false), has_device_policy_(false) { + managed_policy_provider_.reset( + new CloudPolicyProvider( + ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), + this, + POLICY_LEVEL_MANDATORY)); + recommended_policy_provider_.reset( + new CloudPolicyProvider( + ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), + this, + POLICY_LEVEL_RECOMMENDED)); } -CloudPolicyCache::~CloudPolicyCache() {} +CloudPolicyCache::~CloudPolicyCache() { + FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, + observer_list_, OnProviderGoingAway()); +} -void CloudPolicyCache::LoadPolicyFromFile() { +void CloudPolicyCache::LoadFromFile() { // TODO(jkummerow): This method is doing file IO during browser startup. In // the long run it would be better to delay this until the FILE thread exists. - if (!file_util::PathExists(backing_file_path_) || fresh_policy_) { + if (!file_util::PathExists(backing_file_path_) || initialization_complete_) { return; } @@ -136,55 +194,47 @@ void CloudPolicyCache::LoadPolicyFromFile() { return; } // Swap in the new policy information. - if (is_unmanaged_) { - base::AutoLock lock(lock_); - last_policy_refresh_time_ = timestamp; - return; - } else if (cached_response.has_cloud_policy()) { - if (!fresh_policy_) { - base::AutoLock lock(lock_); - // The use of |Swap()| here makes sure that the old value in - // |mandatory_policy_| is deleted when |mandatory_policy| goes out of - // scope. (The same applies to |SetPolicy()| below.) - mandatory_policy_.Swap(&mandatory_policy); - recommended_policy_.Swap(&recommended_policy); - last_policy_refresh_time_ = timestamp; - has_device_policy_ = false; - } + if (cached_response.has_cloud_policy()) { + mandatory_policy_.Swap(&mandatory_policy); + recommended_policy_.Swap(&recommended_policy); + has_device_policy_ = false; } else if (cached_response.has_device_policy()) { scoped_ptr<DictionaryValue> value( DecodeDevicePolicy(cached_response.device_policy())); - if (!fresh_policy_) { - base::AutoLock lock(lock_); - device_policy_.reset(value.release()); - last_policy_refresh_time_ = timestamp; - has_device_policy_ = true; - } + device_policy_.reset(value.release()); + has_device_policy_ = true; } + last_policy_refresh_time_ = timestamp; + initialization_complete_ = true; + + FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, + observer_list_, OnUpdatePolicy()); } -bool CloudPolicyCache::SetPolicy(const em::CloudPolicyResponse& policy) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +void CloudPolicyCache::SetPolicy(const em::CloudPolicyResponse& policy) { + DCHECK(CalledOnValidThread()); + bool initialization_was_not_complete = !initialization_complete_; is_unmanaged_ = false; base::Time timestamp; PolicyMap mandatory_policy; PolicyMap recommended_policy; bool ok = DecodePolicyResponse(policy, &mandatory_policy, &recommended_policy, ×tamp); - if (!ok) { - // TODO(jkummerow): Signal error to PolicyProvider. - return false; - } + if (!ok) + return; + const bool new_policy_differs = - !mandatory_policy.Equals(mandatory_policy_) || - !recommended_policy.Equals(recommended_policy_); - { - base::AutoLock lock(lock_); - mandatory_policy_.Swap(&mandatory_policy); - recommended_policy_.Swap(&recommended_policy); - fresh_policy_ = true; - last_policy_refresh_time_ = timestamp; - has_device_policy_ = false; + !mandatory_policy_.Equals(mandatory_policy) || + !recommended_policy_.Equals(recommended_policy); + mandatory_policy_.Swap(&mandatory_policy); + recommended_policy_.Swap(&recommended_policy); + initialization_complete_ = true; + last_policy_refresh_time_ = timestamp; + has_device_policy_ = false; + + if (new_policy_differs || initialization_was_not_complete) { + FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, + observer_list_, OnUpdatePolicy()); } if (timestamp > base::Time::NowFromSystemTime() + @@ -199,21 +249,23 @@ bool CloudPolicyCache::SetPolicy(const em::CloudPolicyResponse& policy) { FROM_HERE, new PersistPolicyTask(backing_file_path_, policy_copy, NULL, false)); } - return new_policy_differs; } -bool CloudPolicyCache::SetDevicePolicy(const em::DevicePolicyResponse& policy) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +void CloudPolicyCache::SetDevicePolicy(const em::DevicePolicyResponse& policy) { + DCHECK(CalledOnValidThread()); + bool initialization_was_not_complete = !initialization_complete_; is_unmanaged_ = false; DictionaryValue* value = DecodeDevicePolicy(policy); const bool new_policy_differs = !(value->Equals(device_policy_.get())); base::Time now(base::Time::NowFromSystemTime()); - { - base::AutoLock lock(lock_); - device_policy_.reset(value); - fresh_policy_ = true; - last_policy_refresh_time_ = now; - has_device_policy_ = true; + device_policy_.reset(value); + initialization_complete_ = true; + last_policy_refresh_time_ = now; + has_device_policy_ = true; + + if (new_policy_differs || initialization_was_not_complete) { + FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, + observer_list_, OnUpdatePolicy()); } em::DevicePolicyResponse* policy_copy = new em::DevicePolicyResponse; @@ -222,35 +274,29 @@ bool CloudPolicyCache::SetDevicePolicy(const em::DevicePolicyResponse& policy) { BrowserThread::FILE, FROM_HERE, new PersistPolicyTask(backing_file_path_, NULL, policy_copy, false)); - return new_policy_differs; } -DictionaryValue* CloudPolicyCache::GetDevicePolicy() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - base::AutoLock lock(lock_); - return device_policy_->DeepCopy(); +ConfigurationPolicyProvider* CloudPolicyCache::GetManagedPolicyProvider() { + DCHECK(CalledOnValidThread()); + return managed_policy_provider_.get(); } -const PolicyMap* CloudPolicyCache::GetMandatoryPolicy() const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - return &mandatory_policy_; -} - -const PolicyMap* CloudPolicyCache::GetRecommendedPolicy() const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - return &recommended_policy_; +ConfigurationPolicyProvider* CloudPolicyCache::GetRecommendedPolicyProvider() { + DCHECK(CalledOnValidThread()); + return recommended_policy_provider_.get(); } void CloudPolicyCache::SetUnmanaged() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(CalledOnValidThread()); is_unmanaged_ = true; - { - base::AutoLock lock(lock_); - mandatory_policy_.Clear(); - recommended_policy_.Clear(); - device_policy_.reset(new DictionaryValue); - last_policy_refresh_time_ = base::Time::NowFromSystemTime(); - } + mandatory_policy_.Clear(); + recommended_policy_.Clear(); + device_policy_.reset(new DictionaryValue); + last_policy_refresh_time_ = base::Time::NowFromSystemTime(); + + FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, + observer_list_, OnUpdatePolicy()); + BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, diff --git a/chrome/browser/policy/cloud_policy_cache.h b/chrome/browser/policy/cloud_policy_cache.h index 518e3f0..5e7745a 100644 --- a/chrome/browser/policy/cloud_policy_cache.h +++ b/chrome/browser/policy/cloud_policy_cache.h @@ -9,9 +9,10 @@ #include "base/file_path.h" #include "base/gtest_prod_util.h" +#include "base/observer_list.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" -#include "base/synchronization/lock.h" +#include "base/threading/non_thread_safe.h" #include "base/time.h" #include "chrome/browser/policy/configuration_policy_provider.h" #include "chrome/browser/policy/policy_map.h" @@ -33,25 +34,29 @@ namespace em = enterprise_management; // to the service directly, but receives updated policy information through // SetPolicy() calls, which is then persisted and decoded into the internal // Value representation chrome uses. -class CloudPolicyCache { +class CloudPolicyCache : public base::NonThreadSafe { public: + // Used to distinguish mandatory from recommended policies. + enum PolicyLevel { + // Policy is forced upon the user and should always take effect. + POLICY_LEVEL_MANDATORY, + // The value is just a recommendation that the user may override. + POLICY_LEVEL_RECOMMENDED, + }; + explicit CloudPolicyCache(const FilePath& backing_file_path); ~CloudPolicyCache(); // Loads policy information from the backing file. Non-existing or erroneous // cache files are ignored. - void LoadPolicyFromFile(); + void LoadFromFile(); - // Resets the policy information. Returns true if the new policy is different - // from the previously stored policy. - bool SetPolicy(const em::CloudPolicyResponse& policy); - bool SetDevicePolicy(const em::DevicePolicyResponse& policy); + // Resets the policy information. + void SetPolicy(const em::CloudPolicyResponse& policy); + void SetDevicePolicy(const em::DevicePolicyResponse& policy); - // Gets the policy information. Ownership of the return value is transferred - // to the caller. - DictionaryValue* GetDevicePolicy(); - const PolicyMap* GetMandatoryPolicy() const; - const PolicyMap* GetRecommendedPolicy() const; + ConfigurationPolicyProvider* GetManagedPolicyProvider(); + ConfigurationPolicyProvider* GetRecommendedPolicyProvider(); void SetUnmanaged(); bool is_unmanaged() const { @@ -70,7 +75,10 @@ class CloudPolicyCache { } private: + class CloudPolicyProvider; + friend class CloudPolicyCacheTest; + friend class DeviceManagementPolicyCacheTest; friend class DeviceManagementPolicyCacheDecodeTest; // Decodes a CloudPolicyResponse into two (ConfigurationPolicyType -> Value*) @@ -106,19 +114,17 @@ class CloudPolicyCache { // The file in which we store a cached version of the policy information. const FilePath backing_file_path_; - // Protects both |mandatory_policy_| and |recommended_policy_| as well as - // |device_policy_|. - base::Lock lock_; - // Policy key-value information. PolicyMap mandatory_policy_; PolicyMap recommended_policy_; scoped_ptr<DictionaryValue> device_policy_; - // Tracks whether the store received a SetPolicy() call, which overrides any - // information loaded from the file. - bool fresh_policy_; + // Whether initialization has been completed. This is the case when we have + // valid policy, learned that the device is unmanaged or ran into + // unrecoverable errors. + bool initialization_complete_; + // Whether the the server has indicated this device is unmanaged. bool is_unmanaged_; // Tracks whether the cache currently stores |device_policy_| that should be @@ -127,6 +133,15 @@ class CloudPolicyCache { // The time at which the policy was last refreshed. base::Time last_policy_refresh_time_; + + // Policy providers. + scoped_ptr<ConfigurationPolicyProvider> managed_policy_provider_; + scoped_ptr<ConfigurationPolicyProvider> recommended_policy_provider_; + + // Provider observers that are registered with this cache's providers. + ObserverList<ConfigurationPolicyProvider::Observer, true> observer_list_; + + DISALLOW_COPY_AND_ASSIGN(CloudPolicyCache); }; } // namespace policy diff --git a/chrome/browser/policy/cloud_policy_cache_unittest.cc b/chrome/browser/policy/cloud_policy_cache_unittest.cc index d9fc768..158ab36 100644 --- a/chrome/browser/policy/cloud_policy_cache_unittest.cc +++ b/chrome/browser/policy/cloud_policy_cache_unittest.cc @@ -12,11 +12,13 @@ #include "base/scoped_temp_dir.h" #include "base/values.h" #include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/configuration_policy_provider.h" #include "chrome/browser/policy/proto/cloud_policy.pb.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" // TODO(jkummerow): remove this import when removing old DMPC test cases. #include "chrome/browser/policy/proto/device_management_constants.h" #include "chrome/browser/policy/proto/device_management_local.pb.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace policy { @@ -31,6 +33,15 @@ void DecodePolicy(const em::CloudPolicySettings& policy, Value* DecodeIntegerValue(google::protobuf::int64 value); ListValue* DecodeStringList(const em::StringList& string_list); +class MockConfigurationPolicyProviderObserver + : public ConfigurationPolicyProvider::Observer { + public: + MockConfigurationPolicyProviderObserver() {} + virtual ~MockConfigurationPolicyProviderObserver() {} + MOCK_METHOD0(OnUpdatePolicy, void()); + void OnProviderGoingAway() {} +}; + // Tests the device management policy cache. class CloudPolicyCacheTest : public testing::Test { protected: @@ -85,11 +96,35 @@ class CloudPolicyCacheTest : public testing::Test { EXPECT_EQ(size, file_util::WriteFile(test_file(), data.c_str(), size)); } + // Takes ownership of |policy_response|. + void SetPolicy(CloudPolicyCache* cache, + em::CloudPolicyResponse* policy_response, + bool expect_changed_policy) { + scoped_ptr<em::CloudPolicyResponse> policy(policy_response); + ConfigurationPolicyObserverRegistrar registrar; + registrar.Init(cache->GetManagedPolicyProvider(), &observer); + if (expect_changed_policy) + EXPECT_CALL(observer, OnUpdatePolicy()).Times(1); + else + EXPECT_CALL(observer, OnUpdatePolicy()).Times(0); + cache->SetPolicy(*policy); + testing::Mock::VerifyAndClearExpectations(&observer); + } + FilePath test_file() { return temp_dir_.path().AppendASCII("CloudPolicyCacheTest"); } + const PolicyMap& mandatory_policy(const CloudPolicyCache& cache) { + return cache.mandatory_policy_; + } + + const PolicyMap& recommended_policy(const CloudPolicyCache& cache) { + return cache.recommended_policy_; + } + MessageLoop loop_; + MockConfigurationPolicyProviderObserver observer; private: ScopedTempDir temp_dir_; @@ -157,16 +192,16 @@ TEST_F(CloudPolicyCacheTest, DecodeStringList) { TEST_F(CloudPolicyCacheTest, Empty) { CloudPolicyCache cache(test_file()); PolicyMap empty; - EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); - EXPECT_TRUE(empty.Equals(*cache.GetRecommendedPolicy())); + EXPECT_TRUE(empty.Equals(mandatory_policy(cache))); + EXPECT_TRUE(empty.Equals(recommended_policy(cache))); EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); } TEST_F(CloudPolicyCacheTest, LoadNoFile) { CloudPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); PolicyMap empty; - EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); + EXPECT_TRUE(empty.Equals(mandatory_policy(cache))); EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); } @@ -177,9 +212,9 @@ TEST_F(CloudPolicyCacheTest, RejectFuture) { em::PolicyOptions::MANDATORY)); WritePolicy(*policy_response); CloudPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); PolicyMap empty; - EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); + EXPECT_TRUE(empty.Equals(mandatory_policy(cache))); EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); } @@ -189,9 +224,9 @@ TEST_F(CloudPolicyCacheTest, LoadWithFile) { em::PolicyOptions::MANDATORY)); WritePolicy(*policy_response); CloudPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); PolicyMap empty; - EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); + EXPECT_TRUE(empty.Equals(mandatory_policy(cache))); EXPECT_NE(base::Time(), cache.last_policy_refresh_time()); EXPECT_GE(base::Time::Now(), cache.last_policy_refresh_time()); } @@ -203,58 +238,58 @@ TEST_F(CloudPolicyCacheTest, LoadWithData) { em::PolicyOptions::MANDATORY)); WritePolicy(*policy); CloudPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); PolicyMap expected; expected.Set(kPolicyHomepageLocation, Value::CreateStringValue("http://www.example.com")); - EXPECT_TRUE(expected.Equals(*cache.GetMandatoryPolicy())); + EXPECT_TRUE(expected.Equals(mandatory_policy(cache))); } TEST_F(CloudPolicyCacheTest, SetPolicy) { CloudPolicyCache cache(test_file()); - scoped_ptr<em::CloudPolicyResponse> policy( + em::CloudPolicyResponse* policy = CreateHomepagePolicy("http://www.example.com", base::Time::NowFromSystemTime(), - em::PolicyOptions::MANDATORY)); - EXPECT_TRUE(cache.SetPolicy(*policy)); - scoped_ptr<em::CloudPolicyResponse> policy2( + em::PolicyOptions::MANDATORY); + SetPolicy(&cache, policy, true); + em::CloudPolicyResponse* policy2 = CreateHomepagePolicy("http://www.example.com", base::Time::NowFromSystemTime(), - em::PolicyOptions::MANDATORY)); - EXPECT_FALSE(cache.SetPolicy(*policy2)); + em::PolicyOptions::MANDATORY); + SetPolicy(&cache, policy2, false); PolicyMap expected; expected.Set(kPolicyHomepageLocation, Value::CreateStringValue("http://www.example.com")); PolicyMap empty; - EXPECT_TRUE(expected.Equals(*cache.GetMandatoryPolicy())); - EXPECT_TRUE(empty.Equals(*cache.GetRecommendedPolicy())); - policy.reset(CreateHomepagePolicy("http://www.example.com", + EXPECT_TRUE(expected.Equals(mandatory_policy(cache))); + EXPECT_TRUE(empty.Equals(recommended_policy(cache))); + policy = CreateHomepagePolicy("http://www.example.com", base::Time::NowFromSystemTime(), - em::PolicyOptions::RECOMMENDED)); - EXPECT_TRUE(cache.SetPolicy(*policy)); - EXPECT_TRUE(expected.Equals(*cache.GetRecommendedPolicy())); - EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); + em::PolicyOptions::RECOMMENDED); + SetPolicy(&cache, policy, true); + EXPECT_TRUE(expected.Equals(recommended_policy(cache))); + EXPECT_TRUE(empty.Equals(mandatory_policy(cache))); } TEST_F(CloudPolicyCacheTest, ResetPolicy) { CloudPolicyCache cache(test_file()); - scoped_ptr<em::CloudPolicyResponse> policy( + em::CloudPolicyResponse* policy = CreateHomepagePolicy("http://www.example.com", base::Time::NowFromSystemTime(), - em::PolicyOptions::MANDATORY)); - EXPECT_TRUE(cache.SetPolicy(*policy)); + em::PolicyOptions::MANDATORY); + SetPolicy(&cache, policy, true); PolicyMap expected; expected.Set(kPolicyHomepageLocation, Value::CreateStringValue("http://www.example.com")); - EXPECT_TRUE(expected.Equals(*cache.GetMandatoryPolicy())); + EXPECT_TRUE(expected.Equals(mandatory_policy(cache))); - scoped_ptr<em::CloudPolicyResponse> empty_policy( + em::CloudPolicyResponse* empty_policy = CreateHomepagePolicy("", base::Time::NowFromSystemTime(), - em::PolicyOptions::MANDATORY)); - EXPECT_TRUE(cache.SetPolicy(*empty_policy)); + em::PolicyOptions::MANDATORY); + SetPolicy(&cache, empty_policy, true); PolicyMap empty; - EXPECT_TRUE(empty.Equals(*cache.GetMandatoryPolicy())); + EXPECT_TRUE(empty.Equals(mandatory_policy(cache))); } TEST_F(CloudPolicyCacheTest, PersistPolicy) { @@ -271,11 +306,11 @@ TEST_F(CloudPolicyCacheTest, PersistPolicy) { EXPECT_TRUE(file_util::PathExists(test_file())); CloudPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); PolicyMap expected; expected.Set(kPolicyHomepageLocation, Value::CreateStringValue("http://www.example.com")); - EXPECT_TRUE(expected.Equals(*cache.GetMandatoryPolicy())); + EXPECT_TRUE(expected.Equals(mandatory_policy(cache))); } TEST_F(CloudPolicyCacheTest, FreshPolicyOverride) { @@ -286,17 +321,17 @@ TEST_F(CloudPolicyCacheTest, FreshPolicyOverride) { WritePolicy(*policy); CloudPolicyCache cache(test_file()); - scoped_ptr<em::CloudPolicyResponse> updated_policy( + em::CloudPolicyResponse* updated_policy = CreateHomepagePolicy("http://www.chromium.org", base::Time::NowFromSystemTime(), - em::PolicyOptions::MANDATORY)); - EXPECT_TRUE(cache.SetPolicy(*updated_policy)); + em::PolicyOptions::MANDATORY); + SetPolicy(&cache, updated_policy, true); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); PolicyMap expected; expected.Set(kPolicyHomepageLocation, Value::CreateStringValue("http://www.chromium.org")); - EXPECT_TRUE(expected.Equals(*cache.GetMandatoryPolicy())); + EXPECT_TRUE(expected.Equals(mandatory_policy(cache))); } } // namespace policy @@ -363,7 +398,10 @@ class DeviceManagementPolicyCacheTest return temp_dir_.path().AppendASCII("DeviceManagementPolicyCacheTest"); } - protected: + const DictionaryValue* device_policy(const CloudPolicyCache& cache) { + return cache.device_policy_.get(); + } + MessageLoop loop_; private: @@ -375,17 +413,15 @@ class DeviceManagementPolicyCacheTest TEST_F(DeviceManagementPolicyCacheTest, Empty) { CloudPolicyCache cache(test_file()); DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetDevicePolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_TRUE(empty.Equals(device_policy(cache))); EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); } TEST_F(DeviceManagementPolicyCacheTest, LoadNoFile) { CloudPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetDevicePolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_TRUE(empty.Equals(device_policy(cache))); EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); } @@ -394,10 +430,9 @@ TEST_F(DeviceManagementPolicyCacheTest, RejectFuture) { WritePolicy(policy_response, base::Time::NowFromSystemTime() + base::TimeDelta::FromMinutes(5)); CloudPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetDevicePolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_TRUE(empty.Equals(device_policy(cache))); EXPECT_EQ(base::Time(), cache.last_policy_refresh_time()); } @@ -405,10 +440,9 @@ TEST_F(DeviceManagementPolicyCacheTest, LoadWithFile) { em::DevicePolicyResponse policy_response; WritePolicy(policy_response, base::Time::NowFromSystemTime()); CloudPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); DictionaryValue empty; - scoped_ptr<Value> policy(cache.GetDevicePolicy()); - EXPECT_TRUE(empty.Equals(policy.get())); + EXPECT_TRUE(empty.Equals(device_policy(cache))); EXPECT_NE(base::Time(), cache.last_policy_refresh_time()); EXPECT_GE(base::Time::Now(), cache.last_policy_refresh_time()); } @@ -418,27 +452,25 @@ TEST_F(DeviceManagementPolicyCacheTest, LoadWithData) { AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); WritePolicy(policy, base::Time::NowFromSystemTime()); CloudPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); DictionaryValue expected; expected.Set("HomepageLocation", Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); + EXPECT_TRUE(expected.Equals(device_policy(cache))); } TEST_F(DeviceManagementPolicyCacheTest, SetDevicePolicy) { CloudPolicyCache cache(test_file()); em::DevicePolicyResponse policy; AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - EXPECT_TRUE(cache.SetDevicePolicy(policy)); + cache.SetDevicePolicy(policy); em::DevicePolicyResponse policy2; AddStringPolicy(&policy2, "HomepageLocation", "http://www.example.com"); - EXPECT_FALSE(cache.SetDevicePolicy(policy2)); + cache.SetDevicePolicy(policy2); // Does not notify observers. DictionaryValue expected; expected.Set("HomepageLocation", Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); + EXPECT_TRUE(expected.Equals(device_policy(cache))); } TEST_F(DeviceManagementPolicyCacheTest, ResetPolicy) { @@ -446,17 +478,15 @@ TEST_F(DeviceManagementPolicyCacheTest, ResetPolicy) { em::DevicePolicyResponse policy; AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com"); - EXPECT_TRUE(cache.SetDevicePolicy(policy)); + cache.SetDevicePolicy(policy); DictionaryValue expected; expected.Set("HomepageLocation", Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); + EXPECT_TRUE(expected.Equals(device_policy(cache))); - EXPECT_TRUE(cache.SetDevicePolicy(em::DevicePolicyResponse())); - policy_value.reset(cache.GetDevicePolicy()); + cache.SetDevicePolicy(em::DevicePolicyResponse()); DictionaryValue empty; - EXPECT_TRUE(empty.Equals(policy_value.get())); + EXPECT_TRUE(empty.Equals(device_policy(cache))); } TEST_F(DeviceManagementPolicyCacheTest, PersistPolicy) { @@ -471,12 +501,11 @@ TEST_F(DeviceManagementPolicyCacheTest, PersistPolicy) { EXPECT_TRUE(file_util::PathExists(test_file())); CloudPolicyCache cache(test_file()); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); DictionaryValue expected; expected.Set("HomepageLocation", Value::CreateStringValue("http://www.example.com")); - scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); + EXPECT_TRUE(expected.Equals(device_policy(cache))); } TEST_F(DeviceManagementPolicyCacheTest, FreshPolicyOverride) { @@ -488,14 +517,13 @@ TEST_F(DeviceManagementPolicyCacheTest, FreshPolicyOverride) { em::DevicePolicyResponse updated_policy; AddStringPolicy(&updated_policy, "HomepageLocation", "http://www.chromium.org"); - EXPECT_TRUE(cache.SetDevicePolicy(updated_policy)); + cache.SetDevicePolicy(updated_policy); - cache.LoadPolicyFromFile(); + cache.LoadFromFile(); DictionaryValue expected; expected.Set("HomepageLocation", Value::CreateStringValue("http://www.chromium.org")); - scoped_ptr<Value> policy_value(cache.GetDevicePolicy()); - EXPECT_TRUE(expected.Equals(policy_value.get())); + EXPECT_TRUE(expected.Equals(device_policy(cache))); } // Tests proper decoding of policy values. diff --git a/chrome/browser/policy/cloud_policy_controller.cc b/chrome/browser/policy/cloud_policy_controller.cc new file mode 100644 index 0000000..7ace406 --- /dev/null +++ b/chrome/browser/policy/cloud_policy_controller.cc @@ -0,0 +1,309 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/cloud_policy_controller.h" + +#include <algorithm> + +#include "base/message_loop.h" +#include "base/rand_util.h" +#include "base/string_util.h" +#include "chrome/browser/policy/cloud_policy_cache.h" +#include "chrome/browser/policy/cloud_policy_subsystem.h" +#include "chrome/browser/policy/device_management_backend.h" +#include "chrome/browser/policy/proto/device_management_constants.h" + +// Domain names that are known not to be managed. +// We don't register the device when such a user logs in. +static const char* kNonManagedDomains[] = { + "@googlemail.com", + "@gmail.com" +}; + +// Checks the domain part of the given username against the list of known +// non-managed domain names. Returns false if |username| is empty or +// in a domain known not to be managed. +static bool CanBeInManagedDomain(const std::string& username) { + if (username.empty()) { + // This means incognito user in case of ChromiumOS and + // no logged-in user in case of Chromium (SigninService). + return false; + } + for (size_t i = 0; i < arraysize(kNonManagedDomains); i++) { + if (EndsWith(username, kNonManagedDomains[i], true)) { + return false; + } + } + return true; +} + +namespace policy { + +namespace em = enterprise_management; + +// The maximum ratio in percent of the policy refresh rate we use for adjusting +// the policy refresh time instant. The rationale is to avoid load spikes from +// many devices that were set up in sync for some reason. +static const int kPolicyRefreshDeviationFactorPercent = 10; +// Maximum deviation we are willing to accept. +static const int64 kPolicyRefreshDeviationMaxInMilliseconds = 30 * 60 * 1000; + +// These are the base values for delays before retrying after an error. They +// will be doubled each time they are used. +static const int64 kPolicyRefreshErrorDelayInMilliseconds = + 3 * 1000; // 3 seconds + +// Default value for the policy refresh rate. +static const int kPolicyRefreshRateInMilliseconds = + 3 * 60 * 60 * 1000; // 3 hours. + +CloudPolicyController::CloudPolicyController( + CloudPolicyCache* cache, + DeviceManagementBackend* backend, + DeviceTokenFetcher* token_fetcher, + CloudPolicyIdentityStrategy* identity_strategy) + : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + Initialize(cache, + backend, + token_fetcher, + identity_strategy, + kPolicyRefreshRateInMilliseconds, + kPolicyRefreshDeviationFactorPercent, + kPolicyRefreshDeviationMaxInMilliseconds, + kPolicyRefreshErrorDelayInMilliseconds); +} + +CloudPolicyController::~CloudPolicyController() { + token_fetcher_->RemoveObserver(this); + identity_strategy_->RemoveObserver(this); + CancelDelayedWork(); +} + +void CloudPolicyController::SetRefreshRate(int64 refresh_rate_milliseconds) { + policy_refresh_rate_ms_ = refresh_rate_milliseconds; + + // Reschedule the refresh task if necessary. + if (state_ == STATE_POLICY_VALID) + SetState(STATE_POLICY_VALID); +} + +void CloudPolicyController::HandlePolicyResponse( + const em::DevicePolicyResponse& response) { + if (state_ == STATE_TOKEN_UNAVAILABLE) + return; + + cache_->SetDevicePolicy(response); + SetState(STATE_POLICY_VALID); +} + +void CloudPolicyController::HandleCloudPolicyResponse( + const em::CloudPolicyResponse& response) { + if (state_ == STATE_TOKEN_UNAVAILABLE) + return; + + cache_->SetPolicy(response); + SetState(STATE_POLICY_VALID); +} + +void CloudPolicyController::OnError(DeviceManagementBackend::ErrorCode code) { + if (state_ == STATE_TOKEN_UNAVAILABLE) + return; + + if (code == DeviceManagementBackend::kErrorServiceDeviceNotFound || + code == DeviceManagementBackend::kErrorServiceManagementTokenInvalid) { + LOG(WARNING) << "The device token was either invalid or unknown to the " + << "device manager, re-registering device."; + SetState(STATE_TOKEN_UNAVAILABLE); + } else if (code == + DeviceManagementBackend::kErrorServiceManagementNotSupported) { + VLOG(1) << "The device is no longer managed, resetting device token."; + SetState(STATE_TOKEN_UNAVAILABLE); + } else if (!fallback_to_old_protocol_ && + code == DeviceManagementBackend::kErrorRequestInvalid) { + LOG(WARNING) << "Device manager doesn't understand new protocol, falling " + << "back to old request."; + fallback_to_old_protocol_ = true; + SetState(STATE_TOKEN_VALID); // Triggers SendPolicyRequest() immediately. + } else { + LOG(WARNING) << "Could not provide policy from the device manager (error = " + << code << "), will retry in " + << (effective_policy_refresh_error_delay_ms_ / 1000) + << " seconds."; + SetState(STATE_POLICY_ERROR); + } +} + +void CloudPolicyController::OnDeviceTokenAvailable() { + identity_strategy_->OnDeviceTokenAvailable(token_fetcher_->GetDeviceToken()); +} + +void CloudPolicyController::OnDeviceTokenChanged() { + if (identity_strategy_->GetDeviceToken().empty()) + SetState(STATE_TOKEN_UNAVAILABLE); + else + SetState(STATE_TOKEN_VALID); +} + +void CloudPolicyController::OnCredentialsChanged() { + SetState(STATE_TOKEN_UNAVAILABLE); +} + +CloudPolicyController::CloudPolicyController( + CloudPolicyCache* cache, + DeviceManagementBackend* backend, + DeviceTokenFetcher* token_fetcher, + CloudPolicyIdentityStrategy* identity_strategy, + int64 policy_refresh_rate_ms, + int policy_refresh_deviation_factor_percent, + int64 policy_refresh_deviation_max_ms, + int64 policy_refresh_error_delay_ms) + : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + Initialize(cache, + backend, + token_fetcher, + identity_strategy, + policy_refresh_rate_ms, + policy_refresh_deviation_factor_percent, + policy_refresh_deviation_max_ms, + policy_refresh_error_delay_ms); +} + +void CloudPolicyController::Initialize( + CloudPolicyCache* cache, + DeviceManagementBackend* backend, + DeviceTokenFetcher* token_fetcher, + CloudPolicyIdentityStrategy* identity_strategy, + int64 policy_refresh_rate_ms, + int policy_refresh_deviation_factor_percent, + int64 policy_refresh_deviation_max_ms, + int64 policy_refresh_error_delay_ms) { + DCHECK(cache); + + cache_ = cache; + backend_.reset(backend); + token_fetcher_ = token_fetcher; + identity_strategy_ = identity_strategy; + state_ = STATE_TOKEN_UNAVAILABLE; + fallback_to_old_protocol_ = false; + delayed_work_task_ = NULL; + policy_refresh_rate_ms_ = policy_refresh_rate_ms; + policy_refresh_deviation_factor_percent_ = + policy_refresh_deviation_factor_percent; + policy_refresh_deviation_max_ms_ = policy_refresh_deviation_max_ms; + policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms; + effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms; + + token_fetcher_->AddObserver(this); + identity_strategy_->AddObserver(this); + if (!identity_strategy_->GetDeviceToken().empty()) + SetState(STATE_TOKEN_VALID); + else + SetState(STATE_TOKEN_UNAVAILABLE); +} + +void CloudPolicyController::FetchToken() { + std::string username; + std::string auth_token; + std::string device_id = identity_strategy_->GetDeviceID(); + if (identity_strategy_->GetCredentials(&username, &auth_token) && + CanBeInManagedDomain(username)) { + token_fetcher_->FetchToken(auth_token, device_id); + } +} + +void CloudPolicyController::SendPolicyRequest() { + DCHECK(!identity_strategy_->GetDeviceToken().empty()); + if (!fallback_to_old_protocol_) { + em::CloudPolicyRequest policy_request; + policy_request.set_policy_scope(kChromePolicyScope); + backend_->ProcessCloudPolicyRequest(identity_strategy_->GetDeviceToken(), + identity_strategy_->GetDeviceID(), + policy_request, this); + } else { + em::DevicePolicyRequest policy_request; + policy_request.set_policy_scope(kChromePolicyScope); + em::DevicePolicySettingRequest* setting = + policy_request.add_setting_request(); + setting->set_key(kChromeDevicePolicySettingKey); + setting->set_watermark(""); + backend_->ProcessPolicyRequest(identity_strategy_->GetDeviceToken(), + identity_strategy_->GetDeviceID(), + policy_request, this); + } +} + +void CloudPolicyController::DoDelayedWork() { + DCHECK(delayed_work_task_); + delayed_work_task_ = NULL; + + switch (state_) { + case STATE_TOKEN_UNAVAILABLE: + FetchToken(); + return; + case STATE_TOKEN_VALID: + case STATE_POLICY_VALID: + case STATE_POLICY_ERROR: + SendPolicyRequest(); + return; + } + + NOTREACHED() << "Unhandled state" << state_; +} + +void CloudPolicyController::CancelDelayedWork() { + if (delayed_work_task_) { + delayed_work_task_->Cancel(); + delayed_work_task_ = NULL; + } +} + +void CloudPolicyController::SetState( + CloudPolicyController::ControllerState new_state) { + state_ = new_state; + + base::Time now(base::Time::NowFromSystemTime()); + base::Time refresh_at; + base::Time last_refresh(cache_->last_policy_refresh_time()); + if (last_refresh.is_null()) + last_refresh = now; + + // Determine when to take the next step. + switch (state_) { + case STATE_TOKEN_UNAVAILABLE: + case STATE_TOKEN_VALID: + refresh_at = now; + break; + case STATE_POLICY_VALID: + effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms_; + refresh_at = + last_refresh + base::TimeDelta::FromMilliseconds(GetRefreshDelay()); + break; + case STATE_POLICY_ERROR: + refresh_at = now + base::TimeDelta::FromMilliseconds( + effective_policy_refresh_error_delay_ms_); + effective_policy_refresh_error_delay_ms_ *= 2; + if (effective_policy_refresh_error_delay_ms_ > policy_refresh_rate_ms_) + effective_policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_; + break; + } + + // Update the delayed work task. + CancelDelayedWork(); + if (!refresh_at.is_null()) { + int64 delay = std::max<int64>((refresh_at - now).InMilliseconds(), 0); + delayed_work_task_ = method_factory_.NewRunnableMethod( + &CloudPolicyController::DoDelayedWork); + MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_work_task_, + delay); + } +} + +int64 CloudPolicyController::GetRefreshDelay() { + int64 deviation = (policy_refresh_deviation_factor_percent_ * + policy_refresh_rate_ms_) / 100; + deviation = std::min(deviation, policy_refresh_deviation_max_ms_); + return policy_refresh_rate_ms_ - base::RandGenerator(deviation + 1); +} + +} // namespace policy diff --git a/chrome/browser/policy/cloud_policy_controller.h b/chrome/browser/policy/cloud_policy_controller.h new file mode 100644 index 0000000..3375981 --- /dev/null +++ b/chrome/browser/policy/cloud_policy_controller.h @@ -0,0 +1,138 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_CLOUD_POLICY_CONTROLLER_H_ +#define CHROME_BROWSER_POLICY_CLOUD_POLICY_CONTROLLER_H_ +#pragma once + +#include <string> + +#include "base/file_path.h" +#include "base/observer_list.h" +#include "base/scoped_ptr.h" +#include "base/task.h" +#include "base/time.h" +#include "chrome/browser/policy/cloud_policy_identity_strategy.h" +#include "chrome/browser/policy/configuration_policy_provider.h" +#include "chrome/browser/policy/device_management_backend.h" +#include "chrome/browser/policy/device_token_fetcher.h" + +class Profile; +class TokenService; + +namespace policy { + +class CloudPolicyCache; +class DeviceManagementBackend; + +// Coordinates the actions of DeviceTokenFetcher, CloudPolicyIdentityStrategy, +// DeviceManagementBackend, and CloudPolicyCache: calls their methods and +// listens to their callbacks/notifications. +class CloudPolicyController + : public DeviceManagementBackend::DevicePolicyResponseDelegate, + public DeviceTokenFetcher::Observer, + public CloudPolicyIdentityStrategy::Observer { + public: + // Takes ownership of |backend|; the other parameters are weak pointers. + CloudPolicyController(CloudPolicyCache* cache, + DeviceManagementBackend* backend, + DeviceTokenFetcher* token_fetcher, + CloudPolicyIdentityStrategy* identity_strategy); + virtual ~CloudPolicyController(); + + // Sets the refresh rate at which to re-fetch policy information. + void SetRefreshRate(int64 refresh_rate_milliseconds); + + // DevicePolicyResponseDelegate implementation: + virtual void HandlePolicyResponse( + const em::DevicePolicyResponse& response); + virtual void HandleCloudPolicyResponse( + const em::CloudPolicyResponse& response); + virtual void OnError(DeviceManagementBackend::ErrorCode code); + + // DeviceTokenFetcher::Observer implementation: + virtual void OnDeviceTokenAvailable(); + + // CloudPolicyIdentityStrategy::Observer implementation: + virtual void OnDeviceTokenChanged(); + virtual void OnCredentialsChanged(); + + private: + // Indicates the current state the controller is in. + enum ControllerState { + // The controller is initializing, policy information not yet available. + STATE_TOKEN_UNAVAILABLE, + // The token is valid, but policy is yet to be fetched. + STATE_TOKEN_VALID, + // Policy information is available and valid. + STATE_POLICY_VALID, + // The service returned an error when requesting policy, ask again later. + STATE_POLICY_ERROR, + }; + + friend class CloudPolicyControllerTest; + + // More configurable constructor for use by test cases. + CloudPolicyController(CloudPolicyCache* cache, + DeviceManagementBackend* backend, + DeviceTokenFetcher* token_fetcher, + CloudPolicyIdentityStrategy* identity_strategy, + int64 policy_refresh_rate_ms, + int policy_refresh_deviation_factor_percent, + int64 policy_refresh_deviation_max_ms, + int64 policy_refresh_error_delay_ms); + + // Called by constructors to perform shared initialization. + void Initialize(CloudPolicyCache* cache, + DeviceManagementBackend* backend, + DeviceTokenFetcher* token_fetcher, + CloudPolicyIdentityStrategy* identity_strategy, + int64 policy_refresh_rate_ms, + int policy_refresh_deviation_factor_percent, + int64 policy_refresh_deviation_max_ms, + int64 policy_refresh_error_delay_ms); + + // Asks the token fetcher to fetch a new token. + void FetchToken(); + + // Sends a request to the device management backend to fetch policy if one + // isn't already outstanding. + void SendPolicyRequest(); + + // Called back from the delayed work task. Performs whatever action is + // required in the current state, e.g. refreshing policy. + void DoDelayedWork(); + + // Cancels the delayed work task. + void CancelDelayedWork(); + + // Switches to a new state and triggers any appropriate actions. + void SetState(ControllerState new_state); + + // Computes the policy refresh delay to use. + int64 GetRefreshDelay(); + + CloudPolicyCache* cache_; + scoped_ptr<DeviceManagementBackend> backend_; + CloudPolicyIdentityStrategy* identity_strategy_; + DeviceTokenFetcher* token_fetcher_; + ControllerState state_; + bool initial_fetch_done_; + bool fallback_to_old_protocol_; + + int64 policy_refresh_rate_ms_; + int policy_refresh_deviation_factor_percent_; + int64 policy_refresh_deviation_max_ms_; + int64 policy_refresh_error_delay_ms_; + int64 effective_policy_refresh_error_delay_ms_; + + CancelableTask* delayed_work_task_; + ScopedRunnableMethodFactory<CloudPolicyController> method_factory_; + + DISALLOW_COPY_AND_ASSIGN(CloudPolicyController); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_CLOUD_POLICY_CONTROLLER_H_ diff --git a/chrome/browser/policy/cloud_policy_controller_unittest.cc b/chrome/browser/policy/cloud_policy_controller_unittest.cc new file mode 100644 index 0000000..b5181c9 --- /dev/null +++ b/chrome/browser/policy/cloud_policy_controller_unittest.cc @@ -0,0 +1,258 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/cloud_policy_controller.h" + +#include "base/message_loop.h" +#include "base/scoped_temp_dir.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/policy/cloud_policy_cache.h" +#include "chrome/browser/policy/mock_configuration_policy_store.h" +#include "chrome/browser/policy/mock_device_management_backend.h" +#include "policy/policy_constants.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +const char kTestToken[] = "cloud_policy_controller_test_auth_token"; + +namespace policy { + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::InSequence; +using ::testing::Mock; +using ::testing::Return; + +class MockCloudPolicyIdentityStrategy : public CloudPolicyIdentityStrategy { + public: + MockCloudPolicyIdentityStrategy() {} + virtual ~MockCloudPolicyIdentityStrategy() {} + + MOCK_METHOD0(GetDeviceToken, std::string()); + MOCK_METHOD0(GetDeviceID, std::string()); + MOCK_METHOD2(GetCredentials, bool(std::string*, std::string*)); + virtual void OnDeviceTokenAvailable(const std::string&) {} + + private: + DISALLOW_COPY_AND_ASSIGN(MockCloudPolicyIdentityStrategy); +}; + +ACTION_P2(MockCloudPolicyIdentityStrategyGetCredentials, username, auth_token) { + *arg0 = username; + *arg1 = auth_token; + return true; +} + +class MockDeviceTokenFetcher : public DeviceTokenFetcher { + public: + explicit MockDeviceTokenFetcher(CloudPolicyCache* cache) + : DeviceTokenFetcher(NULL, cache) {} + virtual ~MockDeviceTokenFetcher() {} + + MOCK_METHOD0(GetDeviceToken, std::string&()); + MOCK_METHOD2(FetchToken, void(const std::string&, const std::string&)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockDeviceTokenFetcher); +}; + +class CloudPolicyControllerTest : public testing::Test { + public: + CloudPolicyControllerTest() + : ui_thread_(BrowserThread::UI, &loop_), + file_thread_(BrowserThread::FILE, &loop_) {} + + virtual ~CloudPolicyControllerTest() {} + + virtual void SetUp() { + ASSERT_TRUE(temp_user_data_dir_.CreateUniqueTempDir()); + cache_.reset(new CloudPolicyCache( + temp_user_data_dir_.path().AppendASCII("CloudPolicyControllerTest"))); + token_fetcher_.reset(new MockDeviceTokenFetcher(cache_.get())); + } + + virtual void TearDown() { + controller_.reset(); // Unregisters observers. + } + + // Takes ownership of |backend|. + void CreateNewController(DeviceManagementBackend* backend) { + controller_.reset(new CloudPolicyController( + cache_.get(), backend, token_fetcher_.get(), &identity_strategy_)); + } + + void CreateNewController(DeviceManagementBackend* backend, + int64 policy_refresh_rate_ms, + int policy_refresh_deviation_factor_percent, + int64 policy_refresh_deviation_max_ms, + int64 policy_refresh_error_delay_ms) { + controller_.reset(new CloudPolicyController( + cache_.get(), backend, token_fetcher_.get(), &identity_strategy_, + policy_refresh_rate_ms, + policy_refresh_deviation_factor_percent, + policy_refresh_deviation_max_ms, + policy_refresh_error_delay_ms)); + } + + void ExpectHasSpdyPolicy() { + MockConfigurationPolicyStore store; + EXPECT_CALL(store, Apply(_, _)).Times(AtLeast(1)); + cache_->GetManagedPolicyProvider()->Provide(&store); + FundamentalValue expected(true); + ASSERT_TRUE(store.Get(kPolicyDisableSpdy) != NULL); + EXPECT_TRUE(store.Get(kPolicyDisableSpdy)->Equals(&expected)); + } + + void SetupIdentityStrategy(const std::string& device_token, + const std::string& device_id, + const std::string& user_name, + const std::string& auth_token) { + EXPECT_CALL(identity_strategy_, GetDeviceToken()).WillRepeatedly( + Return(device_token)); + EXPECT_CALL(identity_strategy_, GetDeviceID()).WillRepeatedly( + Return(device_id)); + if (!user_name.empty()) { + EXPECT_CALL(identity_strategy_, GetCredentials(_, _)).WillRepeatedly( + MockCloudPolicyIdentityStrategyGetCredentials(user_name, auth_token)); + } + } + + protected: + scoped_ptr<CloudPolicyCache> cache_; + scoped_ptr<CloudPolicyController> controller_; + scoped_ptr<MockDeviceTokenFetcher> token_fetcher_; + MockCloudPolicyIdentityStrategy identity_strategy_; + ScopedTempDir temp_user_data_dir_; + MessageLoop loop_; + + private: + BrowserThread ui_thread_; + BrowserThread file_thread_; + + DISALLOW_COPY_AND_ASSIGN(CloudPolicyControllerTest); +}; + +// If a device token is present when the controller starts up, it should +// fetch and apply policy. +TEST_F(CloudPolicyControllerTest, StartupWithDeviceToken) { + SetupIdentityStrategy("fake_device_token", "device_id", "", ""); + MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); + EXPECT_CALL(*backend, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + CreateNewController(backend); + loop_.RunAllPending(); + ExpectHasSpdyPolicy(); +} + +// If no device token is present when the controller starts up, it should +// instruct the token_fetcher_ to fetch one. +TEST_F(CloudPolicyControllerTest, StartupWithoutDeviceToken) { + SetupIdentityStrategy("", "device_id", "a@b.com", "auth_token"); + EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _)).Times(1); + CreateNewController(NULL); + loop_.RunAllPending(); +} + +// If the current user belongs to a known non-managed domain, no token fetch +// should be initiated. +TEST_F(CloudPolicyControllerTest, StartupUnmanagedUser) { + SetupIdentityStrategy("", "device_id", "DannoHelper@gmail.com", "auth_token"); + EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _)).Times(0); + CreateNewController(NULL); + loop_.RunAllPending(); +} + +// After policy has been fetched successfully, a new fetch should be triggered +// after the refresh interval has timed out. +TEST_F(CloudPolicyControllerTest, RefreshAfterSuccessfulPolicy) { + SetupIdentityStrategy("device_token", "device_id", + "DannoHelperDelegate@b.com", "auth_token"); + MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); + EXPECT_CALL(*backend, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorRequestFailed)); + CreateNewController(backend, 0, 0, 0, 1000 * 1000); + loop_.RunAllPending(); + ExpectHasSpdyPolicy(); +} + +// If poliy fetching failed, it should be retried. +TEST_F(CloudPolicyControllerTest, RefreshAfterError) { + SetupIdentityStrategy("device_token", "device_id", + "DannoHelperDelegateImpl@b.com", "auth_token"); + MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); + EXPECT_CALL(*backend, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorRequestFailed)).WillOnce( + MockDeviceManagementBackendSucceedSpdyCloudPolicy()); + CreateNewController(backend, 1000 * 1000, 0, 0, 0); + loop_.RunAllPending(); + ExpectHasSpdyPolicy(); +} + +// If the backend reports that the device token was invalid, the controller +// should instruct the token fetcher to fetch a new token. +TEST_F(CloudPolicyControllerTest, InvalidToken) { + SetupIdentityStrategy("device_token", "device_id", "standup@ten.am", "auth"); + MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); + EXPECT_CALL(*backend, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorServiceManagementTokenInvalid)); + EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _)).Times(1); + CreateNewController(backend); + loop_.RunAllPending(); +} + +// If the backend reports that the device is unknown to the server, the +// controller should instruct the token fetcher to fetch a new token. +TEST_F(CloudPolicyControllerTest, DeviceNotFound) { + SetupIdentityStrategy("device_token", "device_id", "me@you.com", "auth"); + MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); + EXPECT_CALL(*backend, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorServiceDeviceNotFound)); + EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _)).Times(1); + CreateNewController(backend); + loop_.RunAllPending(); +} + +// If the backend reports that the device is no longer managed, the controller +// shoud instruct the token fetcher to fetch a new token (which will in turn +// set and persist the correct 'unmanaged' state). +TEST_F(CloudPolicyControllerTest, NoLongerManaged) { + SetupIdentityStrategy("device_token", "device_id", "who@what.com", "auth"); + MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); + EXPECT_CALL(*backend, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorServiceManagementNotSupported)); + EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _)).Times(1); + CreateNewController(backend); + loop_.RunAllPending(); +} + +// If the server doesn't support the new protocol, the controller should fall +// back to the old protocol. +TEST_F(CloudPolicyControllerTest, FallbackToOldProtocol) { + SetupIdentityStrategy("device_token", "device_id", "a@b.com", "auth"); + MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); + // If the CloudPolicyRequest fails with kErrorRequestInvalid... + EXPECT_CALL(*backend, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorRequestInvalid)); + // ...the client should fall back to a classic PolicyRequest, + // and remember this fallback for any future request, + // both after successful fetches and after errors. + EXPECT_CALL(*backend, ProcessPolicyRequest(_, _, _, _)).WillOnce( + MockDeviceManagementBackendSucceedBooleanPolicy( + key::kDisableSpdy, true)).WillOnce( + MockDeviceManagementBackendFailPolicy( + DeviceManagementBackend::kErrorHttpStatus)).WillOnce( + Return()); + CreateNewController(backend, 0, 0, 0, 0); + loop_.RunAllPending(); + ExpectHasSpdyPolicy(); +} + +} // namespace policy diff --git a/chrome/browser/policy/cloud_policy_identity_strategy.h b/chrome/browser/policy/cloud_policy_identity_strategy.h new file mode 100644 index 0000000..681d80a --- /dev/null +++ b/chrome/browser/policy/cloud_policy_identity_strategy.h @@ -0,0 +1,83 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_CLOUD_POLICY_IDENTITY_STRATEGY_H_ +#define CHROME_BROWSER_POLICY_CLOUD_POLICY_IDENTITY_STRATEGY_H_ +#pragma once + +#include <string> + +#include "base/observer_list.h" + +namespace policy { + +// Manages a device management token, i.e. an identifier that represents a +// registration with the device management service, and the associated +// credentials. Responsibilities include storing and loading the token from +// disk, observing and triggering relevant notifications. +class CloudPolicyIdentityStrategy { + public: + class Observer { + public: + virtual ~Observer() {} + + // Notifies observers that the effective token for fetching policy has + // changed. The token can be queried by calling GetDeviceToken(). + virtual void OnDeviceTokenChanged() = 0; + + // Authentication credentials for talking to the device management service + // changed. New auth data is available through GetCredentials(). + virtual void OnCredentialsChanged() = 0; + }; + + CloudPolicyIdentityStrategy() {} + virtual ~CloudPolicyIdentityStrategy() {} + + void AddObserver(Observer* obs) { + observer_list_.AddObserver(obs); + } + + void RemoveObserver(Observer* obs) { + observer_list_.RemoveObserver(obs); + } + + // Returns the device management token, if available. Returns the empty string + // if the device token is currently unavailable. + virtual std::string GetDeviceToken() = 0; + + // Returns the device ID for this device. + virtual std::string GetDeviceID() = 0; + + // Retrieves authentication credentials to use when talking to the device + // management service. Returns true if the data is available and writes the + // values to the provided pointers. + virtual bool GetCredentials(std::string* username, + std::string* auth_token) = 0; + + // Notifies the identity strategy that a new token has been fetched. It is up + // to the identity strategy to store the token, decide whether it is going + // to be used, send out an appropriate OnDeviceTokenChanged() notification + // and return the new token in GetDeviceToken() calls. + virtual void OnDeviceTokenAvailable(const std::string& token) = 0; + + protected: + // Notify observers that the effective token has changed. + void NotifyDeviceTokenChanged() { + FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceTokenChanged()); + } + + // Notify observers about authentication data change. + void NotifyAuthChanged() { + FOR_EACH_OBSERVER(Observer, observer_list_, OnCredentialsChanged()); + } + + private: + ObserverList<Observer, true> observer_list_; + + DISALLOW_COPY_AND_ASSIGN(CloudPolicyIdentityStrategy); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_CLOUD_POLICY_IDENTITY_STRATEGY_H_ diff --git a/chrome/browser/policy/cloud_policy_subsystem.cc b/chrome/browser/policy/cloud_policy_subsystem.cc new file mode 100644 index 0000000..3b8291a --- /dev/null +++ b/chrome/browser/policy/cloud_policy_subsystem.cc @@ -0,0 +1,124 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/cloud_policy_subsystem.h" + +#include <algorithm> +#include <string> + +#include "base/command_line.h" +#include "chrome/browser/policy/cloud_policy_cache.h" +#include "chrome/browser/policy/cloud_policy_controller.h" +#include "chrome/browser/policy/cloud_policy_identity_strategy.h" +#include "chrome/browser/policy/configuration_policy_provider.h" +#include "chrome/browser/policy/device_management_service.h" +#include "chrome/browser/policy/device_token_fetcher.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_details.h" +#include "chrome/common/notification_source.h" +#include "chrome/common/notification_type.h" + +namespace { + +// Refresh rate sanity interval bounds. +const int64 kPolicyRefreshRateMinMs = 30 * 60 * 1000; // 30 minutes +const int64 kPolicyRefreshRateMaxMs = 24 * 60 * 60 * 1000; // 1 day + +} // namespace + +namespace policy { + +CloudPolicySubsystem::CloudPolicySubsystem( + const FilePath& policy_cache_file, + CloudPolicyIdentityStrategy* identity_strategy) + : prefs_(NULL) { + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kDeviceManagementUrl)) { + device_management_service_.reset(new DeviceManagementService( + command_line->GetSwitchValueASCII(switches::kDeviceManagementUrl))); + cloud_policy_cache_.reset(new CloudPolicyCache(policy_cache_file)); + cloud_policy_cache_->LoadFromFile(); + + device_token_fetcher_.reset( + new DeviceTokenFetcher(device_management_service_.get(), + cloud_policy_cache_.get())); + + cloud_policy_controller_.reset( + new CloudPolicyController(cloud_policy_cache_.get(), + device_management_service_->CreateBackend(), + device_token_fetcher_.get(), + identity_strategy)); + } +} + +CloudPolicySubsystem::~CloudPolicySubsystem() { + DCHECK(!prefs_); + cloud_policy_controller_.reset(); + device_token_fetcher_.reset(); + cloud_policy_cache_.reset(); + device_management_service_.reset(); +} + +void CloudPolicySubsystem::Initialize( + PrefService* prefs, + const char* refresh_rate_pref_name, + URLRequestContextGetter* request_context) { + DCHECK(!prefs_); + prefs_ = prefs; + + if (device_management_service_.get()) + device_management_service_->Initialize(request_context); + + policy_refresh_rate_.Init(refresh_rate_pref_name, prefs_, this); + UpdatePolicyRefreshRate(); +} + +void CloudPolicySubsystem::Shutdown() { + if (device_management_service_.get()) + device_management_service_->Shutdown(); + cloud_policy_controller_.reset(); + cloud_policy_cache_.reset(); + policy_refresh_rate_.Destroy(); + prefs_ = NULL; +} + +ConfigurationPolicyProvider* CloudPolicySubsystem::GetManagedPolicyProvider() { + if (cloud_policy_cache_.get()) + return cloud_policy_cache_->GetManagedPolicyProvider(); + + return NULL; +} + +ConfigurationPolicyProvider* + CloudPolicySubsystem::GetRecommendedPolicyProvider() { + if (cloud_policy_cache_.get()) + return cloud_policy_cache_->GetRecommendedPolicyProvider(); + + return NULL; +} + +void CloudPolicySubsystem::UpdatePolicyRefreshRate() { + if (cloud_policy_controller_.get()) { + // Clamp to sane values. + int64 refresh_rate = policy_refresh_rate_.GetValue(); + refresh_rate = std::max(kPolicyRefreshRateMinMs, refresh_rate); + refresh_rate = std::min(kPolicyRefreshRateMaxMs, refresh_rate); + cloud_policy_controller_->SetRefreshRate(refresh_rate); + } +} + +void CloudPolicySubsystem::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::PREF_CHANGED && + policy_refresh_rate_.GetPrefName() == + *(Details<std::string>(details).ptr()) && + prefs_ == Source<PrefService>(source).ptr()) { + UpdatePolicyRefreshRate(); + } else { + NOTREACHED(); + } +} + +} // namespace policy diff --git a/chrome/browser/policy/cloud_policy_subsystem.h b/chrome/browser/policy/cloud_policy_subsystem.h new file mode 100644 index 0000000..503e607 --- /dev/null +++ b/chrome/browser/policy/cloud_policy_subsystem.h @@ -0,0 +1,73 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_CLOUD_POLICY_SUBSYSTEM_H_ +#define CHROME_BROWSER_POLICY_CLOUD_POLICY_SUBSYSTEM_H_ +#pragma once + +#include "base/scoped_ptr.h" +#include "chrome/browser/prefs/pref_member.h" +#include "chrome/common/notification_observer.h" + +class FilePath; +class PrefService; +class URLRequestContextGetter; + +namespace policy { + +class CloudPolicyCache; +class CloudPolicyController; +class CloudPolicyIdentityStrategy; +class ConfigurationPolicyProvider; +class DeviceManagementService; +class DeviceTokenFetcher; + +// This class is a container for the infrastructure required to support cloud +// policy. It glues together the backend, the policy controller and manages the +// life cycle of the policy providers. +class CloudPolicySubsystem : public NotificationObserver { + public: + CloudPolicySubsystem(const FilePath& policy_cache_file, + CloudPolicyIdentityStrategy* identity_strategy); + virtual ~CloudPolicySubsystem(); + + // Initializes the subsystem. + void Initialize(PrefService* prefs, + const char* refresh_rate_pref_name, + URLRequestContextGetter* request_context); + + // Shuts the subsystem down. This must be called before threading and network + // infrastructure goes away. + void Shutdown(); + + ConfigurationPolicyProvider* GetManagedPolicyProvider(); + ConfigurationPolicyProvider* GetRecommendedPolicyProvider(); + + private: + // Updates the policy controller with a new refresh rate value. + void UpdatePolicyRefreshRate(); + + // NotificationObserver overrides. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // The pref service that controls the refresh rate. + PrefService* prefs_; + + // Tracks the pref value for the policy refresh rate. + IntegerPrefMember policy_refresh_rate_; + + // Cloud policy infrastructure stuff. + scoped_ptr<DeviceManagementService> device_management_service_; + scoped_ptr<DeviceTokenFetcher> device_token_fetcher_; + scoped_ptr<CloudPolicyCache> cloud_policy_cache_; + scoped_ptr<CloudPolicyController> cloud_policy_controller_; + + DISALLOW_COPY_AND_ASSIGN(CloudPolicySubsystem); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_CLOUD_POLICY_SUBSYSTEM_H_ diff --git a/chrome/browser/policy/configuration_policy_pref_store.cc b/chrome/browser/policy/configuration_policy_pref_store.cc index 0b8445f..a60b45d 100644 --- a/chrome/browser/policy/configuration_policy_pref_store.cc +++ b/chrome/browser/policy/configuration_policy_pref_store.cc @@ -18,10 +18,9 @@ #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/policy/browser_policy_connector.h" #include "chrome/browser/policy/configuration_policy_provider.h" -#include "chrome/browser/policy/configuration_policy_provider_keeper.h" -#include "chrome/browser/policy/device_management_policy_provider.h" -#include "chrome/browser/policy/profile_policy_context.h" +#include "chrome/browser/policy/profile_policy_connector.h" #include "chrome/browser/prefs/pref_value_map.h" #include "chrome/browser/prefs/proxy_config_dictionary.h" #include "chrome/browser/profiles/profile.h" @@ -228,7 +227,7 @@ const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry { Value::TYPE_BOOLEAN, kPolicyDisable3DAPIs, prefs::kDisable3DAPIs }, { Value::TYPE_INTEGER, kPolicyPolicyRefreshRate, - prefs::kPolicyRefreshRate }, + prefs::kPolicyUserPolicyRefreshRate }, { Value::TYPE_BOOLEAN, kPolicyInstantEnabled, prefs::kInstantEnabled }, { Value::TYPE_BOOLEAN, kPolicyDefaultBrowserSettingEnabled, prefs::kDefaultBrowserSettingEnabled }, @@ -738,35 +737,53 @@ void ConfigurationPolicyPrefStore::OnProviderGoingAway() { // static ConfigurationPolicyPrefStore* ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore() { - ConfigurationPolicyProviderKeeper* keeper = - g_browser_process->configuration_policy_provider_keeper(); - return new ConfigurationPolicyPrefStore(keeper->managed_platform_provider()); + BrowserPolicyConnector* connector = + g_browser_process->browser_policy_connector(); + return new ConfigurationPolicyPrefStore( + connector->GetManagedPlatformProvider()); } // static ConfigurationPolicyPrefStore* ConfigurationPolicyPrefStore::CreateManagedCloudPolicyPrefStore( Profile* profile) { + ConfigurationPolicyProvider* provider = NULL; if (profile) { - return new ConfigurationPolicyPrefStore( - profile->GetPolicyContext()->GetDeviceManagementPolicyProvider()); + // For user policy, return the profile's policy provider. + provider = profile->GetPolicyConnector()->GetManagedCloudProvider(); + } else { + // For device policy, return the provider of the browser process. + BrowserPolicyConnector* connector = + g_browser_process->browser_policy_connector(); + provider = connector->GetManagedCloudProvider(); } - return new ConfigurationPolicyPrefStore(NULL); + return new ConfigurationPolicyPrefStore(provider); } // static ConfigurationPolicyPrefStore* ConfigurationPolicyPrefStore::CreateRecommendedPlatformPolicyPrefStore() { - ConfigurationPolicyProviderKeeper* keeper = - g_browser_process->configuration_policy_provider_keeper(); - return new ConfigurationPolicyPrefStore(keeper->recommended_provider()); + BrowserPolicyConnector* connector = + g_browser_process->browser_policy_connector(); + return new ConfigurationPolicyPrefStore( + connector->GetRecommendedPlatformProvider()); } // static ConfigurationPolicyPrefStore* ConfigurationPolicyPrefStore::CreateRecommendedCloudPolicyPrefStore( Profile* profile) { - return new ConfigurationPolicyPrefStore(NULL); + ConfigurationPolicyProvider* provider = NULL; + if (profile) { + // For user policy, return the profile's policy provider. + provider = profile->GetPolicyConnector()->GetRecommendedCloudProvider(); + } else { + // For device policy, return the provider of the browser process. + BrowserPolicyConnector* connector = + g_browser_process->browser_policy_connector(); + provider = connector->GetRecommendedCloudProvider(); + } + return new ConfigurationPolicyPrefStore(provider); } /* static */ diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc index be89d98..a29922d 100644 --- a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc +++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc @@ -229,7 +229,7 @@ INSTANTIATE_TEST_CASE_P( TypeAndName(kPolicyRestoreOnStartup, prefs::kRestoreOnStartup), TypeAndName(kPolicyPolicyRefreshRate, - prefs::kPolicyRefreshRate))); + prefs::kPolicyUserPolicyRefreshRate))); // Test cases for the proxy policy settings. class ConfigurationPolicyPrefStoreProxyTest : public testing::Test { diff --git a/chrome/browser/policy/configuration_policy_provider_keeper.cc b/chrome/browser/policy/configuration_policy_provider_keeper.cc deleted file mode 100644 index 9959f74..0000000 --- a/chrome/browser/policy/configuration_policy_provider_keeper.cc +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/policy/configuration_policy_provider_keeper.h" - -#include "base/path_service.h" -#include "chrome/browser/policy/configuration_policy_pref_store.h" -#include "chrome/browser/policy/configuration_policy_provider.h" -#if defined(OS_WIN) -#include "chrome/browser/policy/configuration_policy_provider_win.h" -#elif defined(OS_MACOSX) -#include "chrome/browser/policy/configuration_policy_provider_mac.h" -#elif defined(OS_POSIX) -#include "chrome/browser/policy/config_dir_policy_provider.h" -#endif -#include "chrome/browser/policy/dummy_configuration_policy_provider.h" -#include "chrome/common/chrome_paths.h" - -namespace policy { - -ConfigurationPolicyProviderKeeper::ConfigurationPolicyProviderKeeper() - : managed_platform_provider_(CreateManagedPlatformProvider()), - device_management_provider_(CreateDeviceManagementProvider()), - recommended_provider_(CreateRecommendedProvider()) { -} - -ConfigurationPolicyProviderKeeper::ConfigurationPolicyProviderKeeper( - ConfigurationPolicyProvider* managed_platform_provider, - ConfigurationPolicyProvider* device_management_provider, - ConfigurationPolicyProvider* recommended_provider) - : managed_platform_provider_(managed_platform_provider), - device_management_provider_(device_management_provider), - recommended_provider_(recommended_provider) { -} - -ConfigurationPolicyProviderKeeper::~ConfigurationPolicyProviderKeeper() {} - -ConfigurationPolicyProvider* - ConfigurationPolicyProviderKeeper::managed_platform_provider() const { - return managed_platform_provider_.get(); -} - -ConfigurationPolicyProvider* - ConfigurationPolicyProviderKeeper::device_management_provider() const { - return device_management_provider_.get(); -} - -ConfigurationPolicyProvider* - ConfigurationPolicyProviderKeeper::recommended_provider() const { - return recommended_provider_.get(); -} - -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 diff --git a/chrome/browser/policy/configuration_policy_provider_keeper.h b/chrome/browser/policy/configuration_policy_provider_keeper.h deleted file mode 100644 index 1156cb4..0000000 --- a/chrome/browser/policy/configuration_policy_provider_keeper.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_KEEPER_H_ -#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_KEEPER_H_ -#pragma once - -#include "base/scoped_ptr.h" -#include "chrome/browser/policy/configuration_policy_provider.h" - -namespace policy { - -// Manages the lifecycle of the shared platform-specific policy providers for -// managed platform, device management and recommended policy. -class ConfigurationPolicyProviderKeeper { - public: - ConfigurationPolicyProviderKeeper(); - // Tests can pass in their own (dummy) providers using this c'tor. - ConfigurationPolicyProviderKeeper( - ConfigurationPolicyProvider* managed_platform_provider, - ConfigurationPolicyProvider* device_management_provider, - ConfigurationPolicyProvider* recommended_provider); - virtual ~ConfigurationPolicyProviderKeeper(); - - ConfigurationPolicyProvider* managed_platform_provider() const; - - ConfigurationPolicyProvider* device_management_provider() const; - - ConfigurationPolicyProvider* recommended_provider() 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(); - - DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderKeeper); -}; - -} // namespace policy - -#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_KEEPER_H_ diff --git a/chrome/browser/policy/device_management_policy_provider.cc b/chrome/browser/policy/device_management_policy_provider.cc deleted file mode 100644 index eaaf4d4..0000000 --- a/chrome/browser/policy/device_management_policy_provider.cc +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/policy/device_management_policy_provider.h" - -#include <algorithm> - -#include "base/command_line.h" -#include "base/file_util.h" -#include "base/path_service.h" -#include "base/rand_util.h" -#include "base/task.h" -#include "chrome/browser/browser_thread.h" -#include "chrome/browser/policy/cloud_policy_cache.h" -#include "chrome/browser/policy/device_management_backend.h" -#include "chrome/browser/policy/profile_policy_context.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" -#include "chrome/common/notification_type.h" - -namespace policy { - -namespace em = enterprise_management; - -// The maximum ratio in percent of the policy refresh rate we use for adjusting -// the policy refresh time instant. The rationale is to avoid load spikes from -// many devices that were set up in sync for some reason. -const int kPolicyRefreshDeviationFactorPercent = 10; -// Maximum deviation we are willing to accept. -const int64 kPolicyRefreshDeviationMaxInMilliseconds = 30 * 60 * 1000; - -// These are the base values for delays before retrying after an error. They -// will be doubled each time they are used. -const int64 kPolicyRefreshErrorDelayInMilliseconds = 3 * 1000; // 3 seconds -const int64 kDeviceTokenRefreshErrorDelayInMilliseconds = 3 * 1000; -// For unmanaged devices, check once per day whether they're still unmanaged. -const int64 kPolicyRefreshUnmanagedDeviceInMilliseconds = 24 * 60 * 60 * 1000; - -const FilePath::StringType kDeviceTokenFilename = FILE_PATH_LITERAL("Token"); -const FilePath::StringType kPolicyFilename = FILE_PATH_LITERAL("Policy"); - -// Calls back into the provider to refresh policy. -class DeviceManagementPolicyProvider::RefreshTask : public CancelableTask { - public: - explicit RefreshTask(DeviceManagementPolicyProvider* provider) - : provider_(provider) {} - - // Task implementation: - virtual void Run() { - if (provider_) - provider_->RefreshTaskExecute(); - } - - // CancelableTask implementation: - virtual void Cancel() { - provider_ = NULL; - } - - private: - DeviceManagementPolicyProvider* provider_; -}; - -DeviceManagementPolicyProvider::DeviceManagementPolicyProvider( - const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list, - DeviceManagementBackend* backend, - Profile* profile) - : ConfigurationPolicyProvider(policy_list) { - Initialize(backend, - profile, - ProfilePolicyContext::kDefaultPolicyRefreshRateInMilliseconds, - kPolicyRefreshDeviationFactorPercent, - kPolicyRefreshDeviationMaxInMilliseconds, - kPolicyRefreshErrorDelayInMilliseconds, - kDeviceTokenRefreshErrorDelayInMilliseconds, - kPolicyRefreshUnmanagedDeviceInMilliseconds); -} - -DeviceManagementPolicyProvider::~DeviceManagementPolicyProvider() { - FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, - observer_list_, - OnProviderGoingAway()); - CancelRefreshTask(); -} - -bool DeviceManagementPolicyProvider::Provide( - ConfigurationPolicyStoreInterface* policy_store) { - if (cache_->has_device_policy()) { - scoped_ptr<DictionaryValue> policies(cache_->GetDevicePolicy()); - ApplyPolicyValueTree(policies.get(), policy_store); - } else { - ApplyPolicyMap(cache_->GetMandatoryPolicy(), policy_store); - // TODO(jkummerow, mnissler): provide recommended policy. - } - return true; -} - -bool DeviceManagementPolicyProvider::IsInitializationComplete() const { - return !cache_->last_policy_refresh_time().is_null(); -} - -void DeviceManagementPolicyProvider::HandlePolicyResponse( - const em::DevicePolicyResponse& response) { - DCHECK(TokenAvailable()); - if (cache_->SetDevicePolicy(response)) { - initial_fetch_done_ = true; - NotifyCloudPolicyUpdate(); - } - SetState(STATE_POLICY_VALID); -} - -void DeviceManagementPolicyProvider::HandleCloudPolicyResponse( - const em::CloudPolicyResponse& response) { - DCHECK(TokenAvailable()); - if (cache_->SetPolicy(response)) { - initial_fetch_done_ = true; - NotifyCloudPolicyUpdate(); - } - SetState(STATE_POLICY_VALID); -} - -void DeviceManagementPolicyProvider::OnError( - DeviceManagementBackend::ErrorCode code) { - DCHECK(TokenAvailable()); - if (code == DeviceManagementBackend::kErrorServiceDeviceNotFound || - code == DeviceManagementBackend::kErrorServiceManagementTokenInvalid) { - LOG(WARNING) << "The device token was either invalid or unknown to the " - << "device manager, re-registering device."; - SetState(STATE_TOKEN_RESET); - } else if (code == - DeviceManagementBackend::kErrorServiceManagementNotSupported) { - VLOG(1) << "The device is no longer managed, resetting device token."; - SetState(STATE_TOKEN_RESET); - } else if (!fallback_to_old_protocol_ && - code == DeviceManagementBackend::kErrorRequestInvalid) { - LOG(WARNING) << "Device management server doesn't understand new protocol," - << " falling back to old request."; - fallback_to_old_protocol_ = true; - SetState(STATE_TOKEN_VALID); // Triggers SendPolicyRequest() immediately. - } else { - LOG(WARNING) << "Could not provide policy from the device manager (error = " - << code << "), will retry in " - << (effective_policy_refresh_error_delay_ms_ / 1000) - << " seconds."; - SetState(STATE_POLICY_ERROR); - } -} - -void DeviceManagementPolicyProvider::OnTokenSuccess() { - DCHECK(!TokenAvailable()); - SetState(STATE_TOKEN_VALID); -} - -void DeviceManagementPolicyProvider::OnTokenError() { - DCHECK(!TokenAvailable()); - LOG(WARNING) << "Could not retrieve device token."; - SetState(STATE_TOKEN_ERROR); -} - -void DeviceManagementPolicyProvider::OnNotManaged() { - DCHECK(!TokenAvailable()); - VLOG(1) << "This device is not managed."; - cache_->SetUnmanaged(); - SetState(STATE_UNMANAGED); -} - -void DeviceManagementPolicyProvider::SetRefreshRate( - int64 refresh_rate_milliseconds) { - policy_refresh_rate_ms_ = refresh_rate_milliseconds; - - // Reschedule the refresh task if necessary. - if (state_ == STATE_POLICY_VALID) - SetState(STATE_POLICY_VALID); -} - -DeviceManagementPolicyProvider::DeviceManagementPolicyProvider( - const PolicyDefinitionList* policy_list, - DeviceManagementBackend* backend, - Profile* profile, - int64 policy_refresh_rate_ms, - int policy_refresh_deviation_factor_percent, - int64 policy_refresh_deviation_max_ms, - int64 policy_refresh_error_delay_ms, - int64 token_fetch_error_delay_ms, - int64 unmanaged_device_refresh_rate_ms) - : ConfigurationPolicyProvider(policy_list) { - Initialize(backend, - profile, - policy_refresh_rate_ms, - policy_refresh_deviation_factor_percent, - policy_refresh_deviation_max_ms, - policy_refresh_error_delay_ms, - token_fetch_error_delay_ms, - unmanaged_device_refresh_rate_ms); -} - -void DeviceManagementPolicyProvider::Initialize( - DeviceManagementBackend* backend, - Profile* profile, - int64 policy_refresh_rate_ms, - int policy_refresh_deviation_factor_percent, - int64 policy_refresh_deviation_max_ms, - int64 policy_refresh_error_delay_ms, - int64 token_fetch_error_delay_ms, - int64 unmanaged_device_refresh_rate_ms) { - DCHECK(profile); - backend_.reset(backend); - profile_ = profile; - fallback_to_old_protocol_ = false; - storage_dir_ = GetOrCreateDeviceManagementDir(profile_->GetPath()); - state_ = STATE_INITIALIZING; - initial_fetch_done_ = false; - refresh_task_ = NULL; - policy_refresh_rate_ms_ = policy_refresh_rate_ms; - policy_refresh_deviation_factor_percent_ = - policy_refresh_deviation_factor_percent; - policy_refresh_deviation_max_ms_ = policy_refresh_deviation_max_ms; - policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms; - effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms; - token_fetch_error_delay_ms_ = token_fetch_error_delay_ms; - effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms; - unmanaged_device_refresh_rate_ms_ = unmanaged_device_refresh_rate_ms; - - const FilePath policy_path = storage_dir_.Append(kPolicyFilename); - cache_.reset(new CloudPolicyCache(policy_path)); - cache_->LoadPolicyFromFile(); - - SetDeviceTokenFetcher(new DeviceTokenFetcher(backend_.get(), profile, - GetTokenPath())); - - if (cache_->is_unmanaged()) { - // This is a non-first login on an unmanaged device. - SetState(STATE_UNMANAGED); - } else { - SetState(STATE_INITIALIZING); - } -} - -void DeviceManagementPolicyProvider::AddObserver( - ConfigurationPolicyProvider::Observer* observer) { - observer_list_.AddObserver(observer); -} - -void DeviceManagementPolicyProvider::RemoveObserver( - ConfigurationPolicyProvider::Observer* observer) { - observer_list_.RemoveObserver(observer); -} - -void DeviceManagementPolicyProvider::SendPolicyRequest() { - if (!fallback_to_old_protocol_) { - em::CloudPolicyRequest policy_request; - policy_request.set_policy_scope(kChromePolicyScope); - backend_->ProcessCloudPolicyRequest(token_fetcher_->GetDeviceToken(), - token_fetcher_->GetDeviceID(), - policy_request, this); - } else { - em::DevicePolicyRequest policy_request; - policy_request.set_policy_scope(kChromePolicyScope); - em::DevicePolicySettingRequest* setting = - policy_request.add_setting_request(); - setting->set_key(kChromeDevicePolicySettingKey); - setting->set_watermark(""); - backend_->ProcessPolicyRequest(token_fetcher_->GetDeviceToken(), - token_fetcher_->GetDeviceID(), - policy_request, this); - } -} - -void DeviceManagementPolicyProvider::RefreshTaskExecute() { - DCHECK(refresh_task_); - refresh_task_ = NULL; - - switch (state_) { - case STATE_INITIALIZING: - token_fetcher_->StartFetching(); - return; - case STATE_TOKEN_VALID: - case STATE_POLICY_VALID: - case STATE_POLICY_ERROR: - SendPolicyRequest(); - return; - case STATE_UNMANAGED: - case STATE_TOKEN_ERROR: - case STATE_TOKEN_RESET: - token_fetcher_->Restart(); - return; - } - - NOTREACHED() << "Unhandled state"; -} - -void DeviceManagementPolicyProvider::CancelRefreshTask() { - if (refresh_task_) { - refresh_task_->Cancel(); - refresh_task_ = NULL; - } -} - -void DeviceManagementPolicyProvider::NotifyCloudPolicyUpdate() { - FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, - observer_list_, - OnUpdatePolicy()); -} - -FilePath DeviceManagementPolicyProvider::GetTokenPath() { - return storage_dir_.Append(kDeviceTokenFilename); -} - -void DeviceManagementPolicyProvider::SetDeviceTokenFetcher( - DeviceTokenFetcher* token_fetcher) { - registrar_.Init(token_fetcher); - registrar_.AddObserver(this); - token_fetcher_ = token_fetcher; -} - -void DeviceManagementPolicyProvider::SetState( - DeviceManagementPolicyProvider::ProviderState new_state) { - state_ = new_state; - - // If this state transition completes the initial policy fetch, let the - // observers now. - if (!initial_fetch_done_ && - new_state != STATE_INITIALIZING && - new_state != STATE_TOKEN_VALID) { - initial_fetch_done_ = true; - NotifyCloudPolicyUpdate(); - } - - base::Time now(base::Time::NowFromSystemTime()); - base::Time refresh_at; - base::Time last_refresh(cache_->last_policy_refresh_time()); - if (last_refresh.is_null()) - last_refresh = now; - - // Determine when to take the next step. - switch (state_) { - case STATE_INITIALIZING: - refresh_at = now; - break; - case STATE_TOKEN_VALID: - effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms_; - refresh_at = now; - break; - case STATE_TOKEN_RESET: - refresh_at = now; - break; - case STATE_UNMANAGED: - refresh_at = last_refresh + - base::TimeDelta::FromMilliseconds(unmanaged_device_refresh_rate_ms_); - break; - case STATE_POLICY_VALID: - effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms_; - refresh_at = - last_refresh + base::TimeDelta::FromMilliseconds(GetRefreshDelay()); - break; - case STATE_TOKEN_ERROR: - refresh_at = now + base::TimeDelta::FromMilliseconds( - effective_token_fetch_error_delay_ms_); - effective_token_fetch_error_delay_ms_ *= 2; - if (effective_token_fetch_error_delay_ms_ > policy_refresh_rate_ms_) - effective_token_fetch_error_delay_ms_ = policy_refresh_rate_ms_; - break; - case STATE_POLICY_ERROR: - refresh_at = now + base::TimeDelta::FromMilliseconds( - effective_policy_refresh_error_delay_ms_); - effective_policy_refresh_error_delay_ms_ *= 2; - if (effective_policy_refresh_error_delay_ms_ > policy_refresh_rate_ms_) - effective_policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_; - break; - } - - // Update the refresh task. - CancelRefreshTask(); - if (!refresh_at.is_null()) { - refresh_task_ = new RefreshTask(this); - int64 delay = std::max<int64>((refresh_at - now).InMilliseconds(), 0); - BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, refresh_task_, - delay); - } -} - -int64 DeviceManagementPolicyProvider::GetRefreshDelay() { - int64 deviation = (policy_refresh_deviation_factor_percent_ * - policy_refresh_rate_ms_) / 100; - deviation = std::min(deviation, policy_refresh_deviation_max_ms_); - return policy_refresh_rate_ms_ - base::RandGenerator(deviation + 1); -} - -bool DeviceManagementPolicyProvider::TokenAvailable() const { - return state_ == STATE_TOKEN_VALID || - state_ == STATE_POLICY_VALID || - state_ == STATE_POLICY_ERROR; -} - -// static -std::string DeviceManagementPolicyProvider::GetDeviceManagementURL() { - return CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kDeviceManagementUrl); -} - -// static -FilePath DeviceManagementPolicyProvider::GetOrCreateDeviceManagementDir( - const FilePath& user_data_dir) { - const FilePath device_management_dir = user_data_dir.Append( - FILE_PATH_LITERAL("Device Management")); - if (!file_util::DirectoryExists(device_management_dir)) { - if (!file_util::CreateDirectory(device_management_dir)) - NOTREACHED(); - } - return device_management_dir; -} - -} // namespace policy diff --git a/chrome/browser/policy/device_management_policy_provider.h b/chrome/browser/policy/device_management_policy_provider.h deleted file mode 100644 index dd09628..0000000 --- a/chrome/browser/policy/device_management_policy_provider.h +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_POLICY_PROVIDER_H_ -#define CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_POLICY_PROVIDER_H_ -#pragma once - -#include <string> - -#include "base/file_path.h" -#include "base/observer_list.h" -#include "base/scoped_ptr.h" -#include "base/time.h" -#include "chrome/browser/policy/configuration_policy_provider.h" -#include "chrome/browser/policy/device_management_backend.h" -#include "chrome/browser/policy/device_token_fetcher.h" - -class Profile; -class TokenService; - -namespace policy { - -class CloudPolicyCache; -class DeviceManagementBackend; - -// Provides policy fetched from the device management server. With the exception -// of the Provide method, which can be called on the FILE thread, all public -// methods must be called on the UI thread. -class DeviceManagementPolicyProvider - : public ConfigurationPolicyProvider, - public DeviceManagementBackend::DevicePolicyResponseDelegate, - public DeviceTokenFetcher::Observer { - public: - DeviceManagementPolicyProvider(const PolicyDefinitionList* policy_list, - DeviceManagementBackend* backend, - Profile* profile); - - virtual ~DeviceManagementPolicyProvider(); - - // ConfigurationPolicyProvider implementation: - virtual bool Provide(ConfigurationPolicyStoreInterface* store); - virtual bool IsInitializationComplete() const; - - // DevicePolicyResponseDelegate implementation: - virtual void HandlePolicyResponse( - const em::DevicePolicyResponse& response); // deprecated. - virtual void HandleCloudPolicyResponse( - const em::CloudPolicyResponse& response); - virtual void OnError(DeviceManagementBackend::ErrorCode code); - - // DeviceTokenFetcher::Observer implementation: - virtual void OnTokenSuccess(); - virtual void OnTokenError(); - virtual void OnNotManaged(); - - // Sets the refresh rate at which to re-fetch policy information. - void SetRefreshRate(int64 refresh_rate_milliseconds); - - private: - // Indicates the current state the provider is in. - enum ProviderState { - // The provider is initializing, policy information not yet available. - STATE_INITIALIZING, - // This device is not managed through policy. - STATE_UNMANAGED, - // The token is valid, but policy is yet to be fetched. - STATE_TOKEN_VALID, - // Policy information is available and valid. - STATE_POLICY_VALID, - // The token was found to be invalid and needs to be obtained again. - STATE_TOKEN_RESET, - // There has been an error fetching the token, retry later. - STATE_TOKEN_ERROR, - // The service returned an error when requesting policy, ask again later. - STATE_POLICY_ERROR, - }; - - class RefreshTask; - - friend class DeviceManagementPolicyProviderTest; - - // More configurable constructor for use by test cases. - DeviceManagementPolicyProvider(const PolicyDefinitionList* policy_list, - DeviceManagementBackend* backend, - Profile* profile, - int64 policy_refresh_rate_ms, - int policy_refresh_deviation_factor_percent, - int64 policy_refresh_deviation_max_ms, - int64 policy_refresh_error_delay_ms, - int64 token_fetch_error_delay_ms, - int64 unmanaged_device_refresh_rate_ms); - - // Called by constructors to perform shared initialization. Initialization - // requiring the IOThread must not be performed directly in this method, - // rather must be deferred until the IOThread is fully initialized. This is - // the case in InitializeAfterIOThreadExists. - void Initialize(DeviceManagementBackend* backend, - Profile* profile, - int64 policy_refresh_rate_ms, - int policy_refresh_deviation_factor_percent, - int64 policy_refresh_deviation_max_ms, - int64 policy_refresh_error_delay_ms, - int64 token_fetch_error_delay_ms, - int64 unmanaged_device_refresh_rate_ms); - - // 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(); - - // Triggers policy refresh, re-requesting device token and policy information - // as necessary. - void RefreshTaskExecute(); - - // Cancels the refresh task. - void CancelRefreshTask(); - - // Notify observers about a policy update. - void NotifyCloudPolicyUpdate(); - - // The path of the device token file. - FilePath GetTokenPath(); - - // Used only by tests. - void SetDeviceTokenFetcher(DeviceTokenFetcher* token_fetcher); - - // Switches to a new state and triggers any appropriate actions. - void SetState(ProviderState new_state); - - // Check whether the current state is one in which the token is available. - bool TokenAvailable() const; - - // Computes the refresh delay to use. - int64 GetRefreshDelay(); - - // Provides the URL at which requests are sent to from the device management - // backend. - static std::string GetDeviceManagementURL(); - - // Returns the path to the sub-directory in the user data directory - // in which device management persistent state is stored. - static FilePath GetOrCreateDeviceManagementDir( - const FilePath& user_data_dir); - - scoped_ptr<DeviceManagementBackend> backend_; - Profile* profile_; // weak - scoped_ptr<CloudPolicyCache> cache_; - bool fallback_to_old_protocol_; - scoped_refptr<DeviceTokenFetcher> token_fetcher_; - DeviceTokenFetcher::ObserverRegistrar registrar_; - ObserverList<ConfigurationPolicyProvider::Observer, true> observer_list_; - FilePath storage_dir_; - ProviderState state_; - bool initial_fetch_done_; - RefreshTask* refresh_task_; - int64 policy_refresh_rate_ms_; - int policy_refresh_deviation_factor_percent_; - int64 policy_refresh_deviation_max_ms_; - int64 policy_refresh_error_delay_ms_; - int64 effective_policy_refresh_error_delay_ms_; - int64 token_fetch_error_delay_ms_; - int64 effective_token_fetch_error_delay_ms_; - int64 unmanaged_device_refresh_rate_ms_; - - DISALLOW_COPY_AND_ASSIGN(DeviceManagementPolicyProvider); -}; - -} // namespace policy - -#endif // CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_POLICY_PROVIDER_H_ diff --git a/chrome/browser/policy/device_management_policy_provider_unittest.cc b/chrome/browser/policy/device_management_policy_provider_unittest.cc deleted file mode 100644 index 8dc3bf4..0000000 --- a/chrome/browser/policy/device_management_policy_provider_unittest.cc +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_util.h" -#include "base/message_loop.h" -#include "base/scoped_temp_dir.h" -#include "chrome/browser/browser_thread.h" -#include "chrome/browser/net/gaia/token_service.h" -#include "chrome/browser/policy/cloud_policy_cache.h" -#include "chrome/browser/policy/configuration_policy_pref_store.h" -#include "chrome/browser/policy/configuration_policy_provider.h" -#include "chrome/browser/policy/device_management_policy_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/test/testing_device_token_fetcher.h" -#include "chrome/test/testing_profile.h" -#include "policy/policy_constants.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -const char kTestToken[] = "device_policy_provider_test_auth_token"; - -namespace policy { - -using ::testing::_; -using ::testing::AtLeast; -using ::testing::InSequence; -using ::testing::Mock; - -class MockConfigurationPolicyObserver - : public ConfigurationPolicyProvider::Observer { - public: - MOCK_METHOD0(OnUpdatePolicy, void()); - void OnProviderGoingAway() {} -}; - -class DeviceManagementPolicyProviderTest : public testing::Test { - public: - DeviceManagementPolicyProviderTest() - : ui_thread_(BrowserThread::UI, &loop_), - file_thread_(BrowserThread::FILE, &loop_) {} - - virtual ~DeviceManagementPolicyProviderTest() {} - - virtual void SetUp() { - profile_.reset(new TestingProfile); - CreateNewProvider(); - EXPECT_TRUE(waiting_for_initial_policies()); - loop_.RunAllPending(); - } - - void CreateNewProvider() { - backend_ = new MockDeviceManagementBackend; - provider_.reset(new DeviceManagementPolicyProvider( - ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), - backend_, - profile_.get())); - provider_->SetDeviceTokenFetcher( - new TestingDeviceTokenFetcher(backend_, - profile_.get(), - provider_->GetTokenPath())); - } - - void CreateNewProvider(int64 policy_refresh_rate_ms, - int policy_refresh_fuzz_factor_percent, - int64 policy_refresh_fuzz_max, - int64 policy_refresh_error_delay_ms, - int64 token_fetch_error_delay_ms, - int64 unmanaged_device_refresh_rate_ms) { - backend_ = new MockDeviceManagementBackend; - provider_.reset(new DeviceManagementPolicyProvider( - ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), - backend_, - profile_.get(), - policy_refresh_rate_ms, - policy_refresh_fuzz_factor_percent, - policy_refresh_fuzz_max, - policy_refresh_error_delay_ms, - token_fetch_error_delay_ms, - unmanaged_device_refresh_rate_ms)); - provider_->SetDeviceTokenFetcher( - new TestingDeviceTokenFetcher(backend_, - profile_.get(), - provider_->GetTokenPath())); - } - - FilePath GetTokenPath() const { - return provider_->GetTokenPath(); - } - - void SimulateSuccessfulLoginAndRunPending() { - // Make sure the notification for the initial policy fetch is generated. - MockConfigurationPolicyObserver observer; - ConfigurationPolicyObserverRegistrar registrar; - registrar.Init(provider_.get(), &observer); - EXPECT_CALL(observer, OnUpdatePolicy()).Times(AtLeast(1)); - - loop_.RunAllPending(); - profile_->GetTokenService()->IssueAuthTokenForTest( - GaiaConstants::kDeviceManagementService, kTestToken); - TestingDeviceTokenFetcher* fetcher = - static_cast<TestingDeviceTokenFetcher*>( - provider_->token_fetcher_.get()); - fetcher->SimulateLogin(kTestManagedDomainUsername); - loop_.RunAllPending(); - } - - void SimulateSuccessfulInitialPolicyFetch() { - MockConfigurationPolicyStore store; - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - SimulateSuccessfulLoginAndRunPending(); - EXPECT_FALSE(waiting_for_initial_policies()); - EXPECT_CALL(store, Apply(kPolicyDisableSpdy, _)).Times(1); - provider_->Provide(&store); - ASSERT_EQ(1U, store.policy_map().size()); - Mock::VerifyAndClearExpectations(backend_); - Mock::VerifyAndClearExpectations(&store); - } - - virtual void TearDown() { - provider_.reset(); - loop_.RunAllPending(); - } - - bool waiting_for_initial_policies() const { - return !provider_->IsInitializationComplete(); - } - - MockDeviceManagementBackend* backend_; // weak - scoped_ptr<DeviceManagementPolicyProvider> provider_; - - protected: - CloudPolicyCache* cache(DeviceManagementPolicyProvider* provider) { - return provider->cache_.get(); - } - - MessageLoop loop_; - - private: - BrowserThread ui_thread_; - BrowserThread file_thread_; - scoped_ptr<Profile> profile_; - - DISALLOW_COPY_AND_ASSIGN(DeviceManagementPolicyProviderTest); -}; - -// If there's no login and no previously-fetched policy, the provider should -// provide an empty policy. -TEST_F(DeviceManagementPolicyProviderTest, InitialProvideNoLogin) { - MockConfigurationPolicyStore store; - EXPECT_CALL(store, Apply(_, _)).Times(0); - provider_->Provide(&store); - EXPECT_TRUE(store.policy_map().empty()); - 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(waiting_for_initial_policies()); - SimulateSuccessfulInitialPolicyFetch(); -} - -// If the login succeed but the device management backend is unreachable, -// there should be no policy provided if there's no previously-fetched policy, -TEST_F(DeviceManagementPolicyProviderTest, EmptyProvideWithFailedBackend) { - MockConfigurationPolicyStore store; - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailRegister( - DeviceManagementBackend::kErrorRequestFailed)); - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).Times(0); - SimulateSuccessfulLoginAndRunPending(); - EXPECT_CALL(store, Apply(kPolicyDisableSpdy, _)).Times(0); - provider_->Provide(&store); - EXPECT_TRUE(store.policy_map().empty()); -} - -// If a policy has been fetched previously, if should be available even before -// the login succeeds or the device management backend is available. -TEST_F(DeviceManagementPolicyProviderTest, SecondProvide) { - // Pre-fetch and persist a policy - SimulateSuccessfulInitialPolicyFetch(); - - // Simulate a app relaunch by constructing a new provider. Policy should be - // refreshed (since that might be the purpose of the app relaunch). - CreateNewProvider(); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - loop_.RunAllPending(); - Mock::VerifyAndClearExpectations(backend_); - - // Simulate another app relaunch, this time against a failing backend. - // Cached policy should still be available. - MockConfigurationPolicyStore store; - CreateNewProvider(); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailPolicy( - DeviceManagementBackend::kErrorRequestFailed)); - SimulateSuccessfulLoginAndRunPending(); - EXPECT_CALL(store, Apply(kPolicyDisableSpdy, _)).Times(1); - provider_->Provide(&store); - ASSERT_EQ(1U, store.policy_map().size()); -} - -// When policy is successfully fetched from the device management server, it -// should force a policy refresh. -TEST_F(DeviceManagementPolicyProviderTest, FetchTriggersRefresh) { - MockConfigurationPolicyObserver observer; - ConfigurationPolicyObserverRegistrar registrar; - registrar.Init(provider_.get(), &observer); - EXPECT_CALL(observer, OnUpdatePolicy()).Times(1); - SimulateSuccessfulInitialPolicyFetch(); -} - -TEST_F(DeviceManagementPolicyProviderTest, ErrorCausesNewRequest) { - { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence. - InSequence s; - CreateNewProvider(1000 * 1000, 0, 0, 0, 0, 0); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailRegister( - DeviceManagementBackend::kErrorRequestFailed)); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailPolicy( - DeviceManagementBackend::kErrorRequestFailed)); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailPolicy( - DeviceManagementBackend::kErrorRequestFailed)); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - } - SimulateSuccessfulLoginAndRunPending(); -} - -TEST_F(DeviceManagementPolicyProviderTest, RefreshPolicies) { - { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence. - InSequence s; - CreateNewProvider(0, 0, 0, 1000 * 1000, 1000, 0); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailPolicy( - DeviceManagementBackend::kErrorRequestFailed)); - } - SimulateSuccessfulLoginAndRunPending(); -} - -// The client should try to re-register the device if the device server reports -// back that it doesn't recognize the device token on a policy request. -TEST_F(DeviceManagementPolicyProviderTest, DeviceNotFound) { - { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence. - InSequence s; - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailPolicy( - DeviceManagementBackend::kErrorServiceDeviceNotFound)); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - } - SimulateSuccessfulLoginAndRunPending(); -} - -// The client should try to re-register the device if the device server reports -// back that the device token is invalid on a policy request. -TEST_F(DeviceManagementPolicyProviderTest, InvalidTokenOnPolicyRequest) { - { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence. - InSequence s; - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailPolicy( - DeviceManagementBackend::kErrorServiceManagementTokenInvalid)); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - } - SimulateSuccessfulLoginAndRunPending(); -} - -// If the client is successfully managed, but the admin stops managing the -// device, the client should notice and throw away the device token and id. -TEST_F(DeviceManagementPolicyProviderTest, DeviceNoLongerManaged) { - { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence. - InSequence s; - CreateNewProvider(0, 0, 0, 0, 0, 1000 * 1000); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailPolicy( - DeviceManagementBackend::kErrorServiceManagementNotSupported)); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailRegister( - DeviceManagementBackend::kErrorServiceManagementNotSupported)); - } - SimulateSuccessfulLoginAndRunPending(); - FilePath token_path(GetTokenPath()); - EXPECT_FALSE(file_util::PathExists(token_path)); -} - -// This test tests three things (see numbered comments below): -TEST_F(DeviceManagementPolicyProviderTest, UnmanagedDevice) { - { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence. - InSequence s; - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailRegister( - DeviceManagementBackend::kErrorServiceManagementNotSupported)); - } - SimulateSuccessfulLoginAndRunPending(); - // (1) The provider's DMPolicyCache should know that the device is not - // managed. - EXPECT_TRUE(cache(provider_.get())->is_unmanaged()); - // (2) On restart, the provider should detect that this is not the first - // login. - CreateNewProvider(1000 * 1000, 0, 0, 0, 0, 0); - EXPECT_FALSE(waiting_for_initial_policies()); - { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence. - InSequence s; - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - } - SimulateSuccessfulLoginAndRunPending(); - // (3) Since the backend call this time returned a device id, the "unmanaged" - // marker should have been deleted. - EXPECT_FALSE(cache(provider_.get())->is_unmanaged()); -} - -TEST_F(DeviceManagementPolicyProviderTest, FallbackToOldProtocol) { - { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence. - InSequence s; - CreateNewProvider(0, 0, 0, 0, 0, 1000 * 1000); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - // If the CloudPolicyRequest fails with kErrorRequestInvalid... - EXPECT_CALL(*backend_, ProcessCloudPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailPolicy( - DeviceManagementBackend::kErrorRequestInvalid)); - // ...the client should fall back to a classic PolicyRequest... - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedBooleanPolicy( - key::kDisableSpdy, true)); - // ...and remember this fallback for any future request, ... - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailPolicy( - DeviceManagementBackend::kErrorHttpStatus)); - // ...both after successful fetches and after errors. - EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailPolicy( - DeviceManagementBackend::kErrorServiceManagementNotSupported)); - // Finally, we set the client to 'unmanaged' to stop its request stream. - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendFailRegister( - DeviceManagementBackend::kErrorServiceManagementNotSupported)); - } - SimulateSuccessfulLoginAndRunPending(); -} - -} // namespace policy diff --git a/chrome/browser/policy/device_management_service.h b/chrome/browser/policy/device_management_service.h index 76a3520..c5f5869 100644 --- a/chrome/browser/policy/device_management_service.h +++ b/chrome/browser/policy/device_management_service.h @@ -51,7 +51,8 @@ class DeviceManagementService : public URLFetcher::Delegate { // Constructs a device management backend for use by client code. Ownership of // the returned backend object is transferred to the caller. - DeviceManagementBackend* CreateBackend(); + // Marked virtual for the benefit of tests. + virtual DeviceManagementBackend* CreateBackend(); // Provides the backend with a request context so it can make actual network // requests. This will also fire any requests queued earlier. diff --git a/chrome/browser/policy/device_policy_identity_strategy.cc b/chrome/browser/policy/device_policy_identity_strategy.cc new file mode 100644 index 0000000..0f19945 --- /dev/null +++ b/chrome/browser/policy/device_policy_identity_strategy.cc @@ -0,0 +1,114 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/device_policy_identity_strategy.h" + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/login/ownership_service.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/net/gaia/token_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/common/net/gaia/gaia_constants.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" + +namespace policy { + +DevicePolicyIdentityStrategy::DevicePolicyIdentityStrategy() + : should_register_(false) { + registrar_.Add(this, + NotificationType::TOKEN_AVAILABLE, + NotificationService::AllSources()); + registrar_.Add(this, + NotificationType::LOGIN_USER_CHANGED, + NotificationService::AllSources()); + registrar_.Add(this, + NotificationType::OWNERSHIP_TAKEN, + NotificationService::AllSources()); + registrar_.Add(this, + NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED, + NotificationService::AllSources()); + + // TODO(mnissler): Figure out how to read the machine id. + machine_id_ = "dummy-cros-machine-ID"; +} + +std::string DevicePolicyIdentityStrategy::GetDeviceToken() { + return device_token_; +} + +std::string DevicePolicyIdentityStrategy::GetDeviceID() { + return machine_id_; +} + +bool DevicePolicyIdentityStrategy::GetCredentials(std::string* username, + std::string* auth_token) { + // Only register if requested. + if (!should_register_) + return false; + + // Need to know the machine id. + if (machine_id_.empty()) + return false; + + // Only fetch credentials (and, subsequently, token/policy) when the owner + // is logged in. + if (!chromeos::OwnershipService::GetSharedInstance()->CurrentUserIsOwner()) + return false; + + // We need to know about the profile of the logged in user. + Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile(); + if (!profile) { + NOTREACHED() << "Current user profile inaccessible"; + return false; + } + + *username = chromeos::UserManager::Get()->logged_in_user().email(); + *auth_token = profile->GetTokenService()->GetTokenForService( + GaiaConstants::kDeviceManagementService); + + return !username->empty() && !auth_token->empty(); +} + +void DevicePolicyIdentityStrategy::OnDeviceTokenAvailable( + const std::string& token) { + DCHECK(!machine_id_.empty()); + + // Reset registration flag, so we only attempt registration once. + should_register_ = false; + + device_token_ = token; + NotifyDeviceTokenChanged(); +} + +void DevicePolicyIdentityStrategy::CheckAndTriggerFetch() { + std::string username; + std::string auth_token; + if (GetCredentials(&username, &auth_token)) + NotifyAuthChanged(); +} + +void DevicePolicyIdentityStrategy::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::TOKEN_AVAILABLE) { + const TokenService::TokenAvailableDetails* token_details = + Details<const TokenService::TokenAvailableDetails>(details).ptr(); + if (token_details->service() == GaiaConstants::kDeviceManagementService) + CheckAndTriggerFetch(); + } else if (type == NotificationType::LOGIN_USER_CHANGED) { + should_register_ = false; + CheckAndTriggerFetch(); + } else if (type == NotificationType::OWNERSHIP_TAKEN) { + should_register_ = true; + CheckAndTriggerFetch(); + } else if (type == NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED) { + CheckAndTriggerFetch(); + } else { + NOTREACHED(); + } +} + +} // namespace policy diff --git a/chrome/browser/policy/device_policy_identity_strategy.h b/chrome/browser/policy/device_policy_identity_strategy.h new file mode 100644 index 0000000..838124d --- /dev/null +++ b/chrome/browser/policy/device_policy_identity_strategy.h @@ -0,0 +1,62 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_DEVICE_POLICY_IDENTITY_STRATEGY_H_ +#define CHROME_BROWSER_POLICY_DEVICE_POLICY_IDENTITY_STRATEGY_H_ +#pragma once + +#include <string> + +#include "chrome/browser/policy/cloud_policy_identity_strategy.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" + +class TokenService; + +namespace policy { + +// DM token provider that stores the token in CrOS signed settings. +class DevicePolicyIdentityStrategy : public CloudPolicyIdentityStrategy, + public NotificationObserver { + public: + DevicePolicyIdentityStrategy(); + virtual ~DevicePolicyIdentityStrategy() {} + + // CloudPolicyIdentityStrategy implementation: + virtual std::string GetDeviceToken(); + virtual std::string GetDeviceID(); + virtual bool GetCredentials(std::string* username, + std::string* auth_token); + virtual void OnDeviceTokenAvailable(const std::string& token); + + private: + // Recheck whether all parameters are available and if so, trigger a + // credentials changed notification. + void CheckAndTriggerFetch(); + + // NotificationObserver method overrides: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // The machine identifier. + std::string machine_id_; + + // Current token. Empty if not available. + std::string device_token_; + + // Whether to try and register. Device policy enrollment does not happen + // automatically except for the case that the device gets claimed. This + // situation is detected by listening for the OWNERSHIP_TAKEN notification. + bool should_register_; + + // Registers the provider for notification of successful Gaia logins. + NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(DevicePolicyIdentityStrategy); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_DEVICE_POLICY_IDENTITY_STRATEGY_H_ diff --git a/chrome/browser/policy/device_token_fetcher.cc b/chrome/browser/policy/device_token_fetcher.cc index 3f977c1..6661d3c 100644 --- a/chrome/browser/policy/device_token_fetcher.cc +++ b/chrome/browser/policy/device_token_fetcher.cc @@ -4,52 +4,19 @@ #include "chrome/browser/policy/device_token_fetcher.h" -#include "base/file_util.h" -#include "base/path_service.h" -#include "base/singleton.h" -#include "base/string_util.h" -#include "chrome/browser/net/gaia/token_service.h" -#include "chrome/browser/policy/proto/device_management_local.pb.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" -#include "chrome/common/notification_source.h" -#include "chrome/common/notification_type.h" +#include <algorithm> -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/user_manager.h" -#else -#include "chrome/browser/browser_signin.h" -#endif +#include "base/message_loop.h" +#include "chrome/browser/policy/cloud_policy_cache.h" +#include "chrome/browser/policy/device_management_service.h" +#include "chrome/browser/policy/proto/device_management_local.pb.h" namespace { -// Domain names that are known not to be managed. -// We don't register the device when such a user logs in. -const char* kNonManagedDomains[] = { - "@googlemail.com", - "@gmail.com" -}; - -// Checks the domain part of the given username against the list of known -// non-managed domain names. Returns false if |username| is empty or its -// in a domain known not to be managed. -bool CanBeInManagedDomain(const std::string& username) { - if (username.empty()) { - // This means incognito user in case of ChromiumOS and - // no logged-in user in case of Chromium (SigninService). - return false; - } - for (size_t i = 0; i < arraysize(kNonManagedDomains); i++) { - if (EndsWith(username, kNonManagedDomains[i], true)) { - return false; - } - } - return true; -} +// Retry after 3 seconds (with exponential backoff) after token fetch errors. +const int64 kTokenFetchErrorDelayMilliseconds = 3 * 1000; +// For unmanaged devices, check once per day whether they're still unmanaged. +const int64 kUnmanagedDeviceRefreshRateMilliseconds = 24 * 60 * 60 * 1000; } // namespace @@ -57,284 +24,155 @@ namespace policy { namespace em = enterprise_management; -DeviceTokenFetcher::ObserverRegistrar::ObserverRegistrar() {} - -DeviceTokenFetcher::ObserverRegistrar::~ObserverRegistrar() { - RemoveAll(); +DeviceTokenFetcher::DeviceTokenFetcher( + DeviceManagementService* service, + CloudPolicyCache* cache) + : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + Initialize(service, + cache, + kTokenFetchErrorDelayMilliseconds, + kUnmanagedDeviceRefreshRateMilliseconds); } -void DeviceTokenFetcher::ObserverRegistrar::Init( - DeviceTokenFetcher* token_fetcher) { - RemoveAll(); - token_fetcher_ = token_fetcher; +DeviceTokenFetcher::DeviceTokenFetcher( + DeviceManagementService* service, + CloudPolicyCache* cache, + int64 token_fetch_error_delay_ms, + int64 unmanaged_device_refresh_rate_ms) + : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + Initialize(service, + cache, + token_fetch_error_delay_ms, + unmanaged_device_refresh_rate_ms); } -void DeviceTokenFetcher::ObserverRegistrar::AddObserver( - DeviceTokenFetcher::Observer* observer) { - observers_.push_back(observer); - token_fetcher_->AddObserver(observer); +DeviceTokenFetcher::~DeviceTokenFetcher() { + CancelRetryTask(); } -void DeviceTokenFetcher::ObserverRegistrar::RemoveAll() { - for (std::vector<DeviceTokenFetcher::Observer*>::iterator it = - observers_.begin(); it != observers_.end(); ++it) { - token_fetcher_->RemoveObserver(*it); - } - observers_.clear(); +void DeviceTokenFetcher::FetchToken(const std::string& auth_token, + const std::string& device_id) { + SetState(STATE_INACTIVE); + auth_token_ = auth_token; + device_id_ = device_id; + FetchTokenInternal(); } -DeviceTokenFetcher::DeviceTokenFetcher( - DeviceManagementBackend* backend, - Profile* profile, - const FilePath& token_path) - : profile_(profile), - token_path_(token_path), - backend_(backend), - state_(kStateNotStarted), - device_token_load_complete_event_(true, false) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - TokenService* token_service = profile_->GetTokenService(); - auth_token_ = token_service->GetTokenForService( - GaiaConstants::kDeviceManagementService); - - registrar_.Add(this, - NotificationType::TOKEN_AVAILABLE, - Source<TokenService>(token_service)); - // Register for the event of user login. The device management token won't - // be fetched until we know the domain of the currently logged in user. -#if defined(OS_CHROMEOS) - registrar_.Add(this, - NotificationType::LOGIN_USER_CHANGED, - NotificationService::AllSources()); -#else - registrar_.Add(this, - NotificationType::GOOGLE_SIGNIN_SUCCESSFUL, - Source<Profile>(profile_)); -#endif +void DeviceTokenFetcher::FetchTokenInternal() { + DCHECK(state_ != STATE_TOKEN_AVAILABLE); + DCHECK(!auth_token_.empty() && !device_id_.empty()); + // Construct a new backend, which will discard any previous requests. + backend_.reset(service_->CreateBackend()); + em::DeviceRegisterRequest request; + backend_->ProcessRegisterRequest(auth_token_, device_id_, request, this); } -DeviceTokenFetcher::~DeviceTokenFetcher() {} +const std::string& DeviceTokenFetcher::GetDeviceToken() { + return device_token_; +} -void DeviceTokenFetcher::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (type == NotificationType::TOKEN_AVAILABLE) { - if (Source<TokenService>(source).ptr() == profile_->GetTokenService()) { - const TokenService::TokenAvailableDetails* token_details = - Details<const TokenService::TokenAvailableDetails>(details).ptr(); - if (token_details->service() == GaiaConstants::kDeviceManagementService) { - if (!HasAuthToken()) { - auth_token_ = token_details->token(); - SendServerRequestIfPossible(); - } - } - } -#if defined(OS_CHROMEOS) - } else if (type == NotificationType::LOGIN_USER_CHANGED) { - SendServerRequestIfPossible(); -#else - } else if (type == NotificationType::GOOGLE_SIGNIN_SUCCESSFUL) { - if (profile_ == Source<Profile>(source).ptr()) { - SendServerRequestIfPossible(); - } -#endif - } else { - NOTREACHED(); - } +void DeviceTokenFetcher::AddObserver(DeviceTokenFetcher::Observer* observer) { + observer_list_.AddObserver(observer); } -std::string DeviceTokenFetcher::GetCurrentUser() { -#if defined(OS_CHROMEOS) - return chromeos::UserManager::Get()->logged_in_user().email(); -#else - return profile_->GetBrowserSignin()->GetSignedInUsername(); -#endif +void DeviceTokenFetcher::RemoveObserver( + DeviceTokenFetcher::Observer* observer) { + observer_list_.RemoveObserver(observer); } void DeviceTokenFetcher::HandleRegisterResponse( const em::DeviceRegisterResponse& response) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK_EQ(kStateRequestingDeviceTokenFromServer, state_); if (response.has_device_management_token()) { device_token_ = response.device_management_token(); - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - NewRunnableFunction(&WriteDeviceTokenToDisk, - token_path_, - device_token_, - device_id_)); - SetState(kStateHasDeviceToken); + SetState(STATE_TOKEN_AVAILABLE); } else { NOTREACHED(); - SetState(kStateFailure); + SetState(STATE_ERROR); } } void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // For privacy reasons, delete all identifying data when this device is not - // managed. if (code == DeviceManagementBackend::kErrorServiceManagementNotSupported) { - device_token_ = std::string(); - device_id_ = std::string(); - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - // The Windows compiler needs explicit template instantiation. - NewRunnableFunction<bool(*)(const FilePath&, bool), FilePath, bool>( - &file_util::Delete, token_path_, false)); - SetState(kStateNotManaged); - return; + cache_->SetUnmanaged(); + SetState(STATE_UNMANAGED); } - SetState(kStateFailure); + SetState(STATE_ERROR); } -void DeviceTokenFetcher::Restart() { - // Complain if there's currently an asynchronous operation going on. - DCHECK(state_ == kStateNotStarted || - state_ == kStateHasDeviceToken || - state_ == kStateFailure || - state_ == kStateNotManaged); - device_token_.clear(); - device_token_load_complete_event_.Reset(); - MakeReadyToRequestDeviceToken(); -} +void DeviceTokenFetcher::Initialize(DeviceManagementService* service, + CloudPolicyCache* cache, + int64 token_fetch_error_delay_ms, + int64 unmanaged_device_refresh_rate_ms) { + service_ = service; + cache_ = cache; + token_fetch_error_delay_ms_ = token_fetch_error_delay_ms; + effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms; + unmanaged_device_refresh_rate_ms_ = unmanaged_device_refresh_rate_ms; + state_ = STATE_INACTIVE; + retry_task_ = NULL; -void DeviceTokenFetcher::StartFetching() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (state_ == kStateNotStarted) { - SetState(kStateLoadDeviceTokenFromDisk); - // The file calls for loading the persisted token must be deferred to the - // FILE thread. - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - NewRunnableMethod(this, - &DeviceTokenFetcher::AttemptTokenLoadFromDisk)); - } -} - -void DeviceTokenFetcher::AttemptTokenLoadFromDisk() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - if (file_util::PathExists(token_path_)) { - std::string data; - em::DeviceCredentials device_credentials; - if (file_util::ReadFileToString(token_path_, &data) && - device_credentials.ParseFromArray(data.c_str(), data.size())) { - device_token_ = device_credentials.device_token(); - device_id_ = device_credentials.device_id(); - if (!device_token_.empty() && !device_id_.empty()) { - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - NewRunnableMethod(this, - &DeviceTokenFetcher::SetState, - kStateHasDeviceToken)); - return; - } - } - } - - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - NewRunnableMethod(this, - &DeviceTokenFetcher::MakeReadyToRequestDeviceToken)); -} - -void DeviceTokenFetcher::MakeReadyToRequestDeviceToken() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - SetState(kStateReadyToRequestDeviceTokenFromServer); - SendServerRequestIfPossible(); -} - -void DeviceTokenFetcher::SendServerRequestIfPossible() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - std::string username = GetCurrentUser(); - if (state_ == kStateReadyToRequestDeviceTokenFromServer - && HasAuthToken() - && backend_ - && !username.empty()) { - if (CanBeInManagedDomain(username)) { - em::DeviceRegisterRequest register_request; - SetState(kStateRequestingDeviceTokenFromServer); - backend_->ProcessRegisterRequest(auth_token_, - GetDeviceID(), - register_request, - this); - } else { - SetState(kStateNotManaged); - } - } -} - -bool DeviceTokenFetcher::IsTokenPending() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - return !device_token_load_complete_event_.IsSignaled(); -} - -std::string DeviceTokenFetcher::GetDeviceToken() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - device_token_load_complete_event_.Wait(); - return device_token_; -} - -std::string DeviceTokenFetcher::GetDeviceID() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // As long as access to this is only allowed from the UI thread, no explicit - // locking is necessary to prevent the ID from being generated twice. - if (device_id_.empty()) - device_id_ = GenerateNewDeviceID(); - return device_id_; + if (cache_->is_unmanaged()) + SetState(STATE_UNMANAGED); } void DeviceTokenFetcher::SetState(FetcherState state) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (state_ == state) - return; state_ = state; - if (state == kStateFailure) { - device_token_load_complete_event_.Signal(); - NotifyTokenError(); - } else if (state == kStateNotManaged) { - device_token_load_complete_event_.Signal(); - NotifyNotManaged(); - } else if (state == kStateHasDeviceToken) { - device_token_load_complete_event_.Signal(); - NotifyTokenSuccess(); + if (state_ != STATE_ERROR) + effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms_; + + base::Time delayed_work_at; + switch (state_) { + case STATE_INACTIVE: + device_token_.clear(); + auth_token_.clear(); + device_id_.clear(); + break; + case STATE_TOKEN_AVAILABLE: + FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceTokenAvailable()); + break; + case STATE_UNMANAGED: + delayed_work_at = cache_->last_policy_refresh_time() + + base::TimeDelta::FromMilliseconds(unmanaged_device_refresh_rate_ms_); + break; + case STATE_ERROR: + delayed_work_at = base::Time::Now() + + base::TimeDelta::FromMilliseconds( + effective_token_fetch_error_delay_ms_); + effective_token_fetch_error_delay_ms_ *= 2; + break; } -} -void DeviceTokenFetcher::GetDeviceTokenPath(FilePath* token_path) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - *token_path = token_path_; + CancelRetryTask(); + if (!delayed_work_at.is_null()) { + base::Time now(base::Time::Now()); + int64 delay = std::max<int64>((delayed_work_at - now).InMilliseconds(), 0); + retry_task_ = method_factory_.NewRunnableMethod( + &DeviceTokenFetcher::ExecuteRetryTask); + MessageLoop::current()->PostDelayedTask(FROM_HERE, retry_task_, + delay); + } } -bool DeviceTokenFetcher::IsTokenValid() const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - return state_ == kStateHasDeviceToken; -} +void DeviceTokenFetcher::ExecuteRetryTask() { + DCHECK(retry_task_); + retry_task_ = NULL; -// static -void DeviceTokenFetcher::WriteDeviceTokenToDisk( - const FilePath& path, - const std::string& device_token, - const std::string& device_id) { - em::DeviceCredentials device_credentials; - device_credentials.set_device_token(device_token); - device_credentials.set_device_id(device_id); - std::string data; - bool no_error = device_credentials.SerializeToString(&data); - DCHECK(no_error); - file_util::WriteFile(path, data.c_str(), data.length()); + switch (state_) { + case STATE_INACTIVE: + case STATE_TOKEN_AVAILABLE: + break; + case STATE_UNMANAGED: + case STATE_ERROR: + FetchTokenInternal(); + break; + } } -// static -std::string DeviceTokenFetcher::GenerateNewDeviceID() { - return guid::GenerateGUID(); +void DeviceTokenFetcher::CancelRetryTask() { + if (retry_task_) { + retry_task_->Cancel(); + retry_task_ = NULL; + } } } // namespace policy diff --git a/chrome/browser/policy/device_token_fetcher.h b/chrome/browser/policy/device_token_fetcher.h index ae22f3d..0501433 100644 --- a/chrome/browser/policy/device_token_fetcher.h +++ b/chrome/browser/policy/device_token_fetcher.h @@ -7,20 +7,17 @@ #pragma once #include <string> -#include <vector> -#include "base/file_path.h" #include "base/observer_list.h" -#include "base/ref_counted.h" -#include "base/synchronization/waitable_event.h" +#include "base/scoped_ptr.h" +#include "base/task.h" #include "chrome/browser/policy/device_management_backend.h" -#include "chrome/common/notification_observer.h" -#include "chrome/common/notification_registrar.h" - -class Profile; namespace policy { +class CloudPolicyCache; +class DeviceManagementService; + namespace em = enterprise_management; // Fetches the device token that can be used for policy requests with the device @@ -29,170 +26,112 @@ namespace em = enterprise_management; // fetcher is shared as a singleton by all users of the device management token // to ensure they all get the same token. class DeviceTokenFetcher - : public NotificationObserver, - public DeviceManagementBackend::DeviceRegisterResponseDelegate, - public base::RefCountedThreadSafe<DeviceTokenFetcher> { + : public DeviceManagementBackend::DeviceRegisterResponseDelegate { public: class Observer { public: - virtual void OnTokenSuccess() = 0; - virtual void OnTokenError() = 0; - virtual void OnNotManaged() = 0; virtual ~Observer() {} + virtual void OnDeviceTokenAvailable() = 0; }; - class ObserverRegistrar { - public: - ObserverRegistrar(); - ~ObserverRegistrar(); - - void Init(DeviceTokenFetcher* token_fetcher); - void AddObserver(DeviceTokenFetcher::Observer* observer); - void RemoveAll(); - private: - DeviceTokenFetcher* token_fetcher_; - std::vector<DeviceTokenFetcher::Observer*> observers_; - }; - - // Requests to the device management server are sent through |backend|. It - // obtains the authentication token from |token_service|. The fetcher stores - // the device token to |token_path| once it's retrieved from the server. - DeviceTokenFetcher(DeviceManagementBackend* backend, - Profile* profile, - const FilePath& token_path); + // |service| is used to talk to the device management service and |cache| is + // used to persist whether the device is unmanaged. + DeviceTokenFetcher(DeviceManagementService* service, + CloudPolicyCache* cache); + // Version for tests that allows to set timing paramters. + DeviceTokenFetcher(DeviceManagementService* service, + CloudPolicyCache* cache, + int64 token_fetch_error_delay_ms, + int64 unmanaged_device_refresh_rate_ms); virtual ~DeviceTokenFetcher(); - // NotificationObserver method overrides: - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); + // Starts fetching a token. + // Declared virtual so it can be overridden by mocks. + virtual void FetchToken(const std::string& auth_token, + const std::string& device_id); + + // Returns the device management token or the empty string if not available. + // Declared virtual so it can be overridden by mocks. + virtual const std::string& GetDeviceToken(); + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); // DeviceManagementBackend::DeviceRegisterResponseDelegate method overrides: virtual void HandleRegisterResponse( const em::DeviceRegisterResponse& response); virtual void OnError(DeviceManagementBackend::ErrorCode code); - // Re-initializes this DeviceTokenFetcher - void Restart(); - - // Called by subscribers of the device management token to indicate that they - // will need the token in the future. Must be called on the UI thread. - void StartFetching(); - - // Returns true if there is a pending token request to the device management - // server. - bool IsTokenPending(); - - // Returns the device management token for this device, blocking until - // outstanding requests to the device management server are satisfied. In the - // case that the token could not be fetched, an empty string is returned. - std::string GetDeviceToken(); - - // Returns the device ID for this device. If no such ID has been set yet, a - // new ID is generated and returned. - std::string GetDeviceID(); - - // True if the fetcher has a valid AuthToken for the device management server. - bool HasAuthToken() const { return !auth_token_.empty(); } - - // True if the device token has been fetched and is valid. - bool IsTokenValid() const; - - protected: - // Returns the email address of the currently logged-in user. - virtual std::string GetCurrentUser(); - - // Used to identify GOOGLE_SIGNIN_SUCCESSFUL notifications from the owning - // profile, and to query for the current username. - Profile* profile_; // weak - private: friend class DeviceTokenFetcherTest; // The different states that the fetcher can be in during the process of - // getting the device token. + // getting the device token. |state_| is initialized to INACTIVE, depending + // on the result of a token fetching attempt can transition to either of + // TOKEN_AVAILABLE, UNMANAGED, or ERROR. The first attempt must be triggered + // externally. When |state_| is UNMANAGED, a new fetching attempt is + // performed every |unmanaged_device_refresh_rate_ms_|; when it's ERROR, + // a new attempt is done after |effective_token_fetch_error_delay_ms_|. enum FetcherState { - kStateNotStarted, - kStateLoadDeviceTokenFromDisk, - kStateReadyToRequestDeviceTokenFromServer, - kStateRequestingDeviceTokenFromServer, - kStateHasDeviceToken, - kStateFailure, - kStateNotManaged, + // Fetcher inactive. + STATE_INACTIVE, + // Token available. + STATE_TOKEN_AVAILABLE, + // Device unmanaged. + STATE_UNMANAGED, + // Error, retry later. + STATE_ERROR, }; - // Moves the fetcher into a new state. If the fetcher has the device token - // or is moving into the failure state, callers waiting on WaitForToken - // are unblocked. - void SetState(FetcherState state); - - // Returns the full path to the file that persists the device manager token. - void GetDeviceTokenPath(FilePath* token_path) const; - - // Tries to load the device token from disk. Must be called on the FILE - // thread. - void AttemptTokenLoadFromDisk(); - - // Called if it's not possible to load the device token from disk. Sets the - // fetcher in a state that's ready to register the device with the device - // management server and receive the device token in return. If the AuthToken - // for the device management server is available, initiate the server - // request. - void MakeReadyToRequestDeviceToken(); - - // Issues a registration request to the server if both the fetcher is in the - // ready-to-request state and the device management server AuthToken is - // available. - void SendServerRequestIfPossible(); + // Common initialization helper. + void Initialize(DeviceManagementService* service, + CloudPolicyCache* cache, + int64 token_fetch_error_delay_ms, + int64 unmanaged_device_refresh_rate_ms); - void AddObserver(Observer* obs) { - observer_list_.AddObserver(obs); - } + // Moves the fetcher into a new state. + void SetState(FetcherState state); - void RemoveObserver(Observer* obs) { - observer_list_.RemoveObserver(obs); - } + // Resets |backend_|, then uses |auth_token_| and |device_id_| to perform + // an actual token fetch. + void FetchTokenInternal(); - void NotifyTokenSuccess() { - FOR_EACH_OBSERVER(Observer, observer_list_, OnTokenSuccess()); - } + // Called back from the |retry_task_|. + void ExecuteRetryTask(); - void NotifyTokenError() { - FOR_EACH_OBSERVER(Observer, observer_list_, OnTokenError()); - } + // Cancels the |retry_task_|. + void CancelRetryTask(); - void NotifyNotManaged() { - FOR_EACH_OBSERVER(Observer, observer_list_, OnNotManaged()); - } + // Service and backend. A new backend is created whenever the fetcher gets + // reset. + DeviceManagementService* service_; // weak + scoped_ptr<DeviceManagementBackend> backend_; - // Saves the device management token to disk once it has been retrieved from - // the server. Must be called on the FILE thread. - static void WriteDeviceTokenToDisk(const FilePath& path, - const std::string& token, - const std::string& device_id); + // Reference to the cache. Used to persist and read unmanaged state. + CloudPolicyCache* cache_; - // Generates a new device ID used to register the device with the device - // management server and generate the device token. - static std::string GenerateNewDeviceID(); + // Refresh parameters. + int64 token_fetch_error_delay_ms_; + int64 effective_token_fetch_error_delay_ms_; + int64 unmanaged_device_refresh_rate_ms_; - ObserverList<Observer, true> observer_list_; - FilePath token_path_; - DeviceManagementBackend* backend_; // weak + // State the fetcher is currently in. FetcherState state_; + + // Current device token. std::string device_token_; - std::string device_id_; - // Contains the AuthToken for the device management server. Empty if the - // AuthToken hasn't been issued yet or that was an error getting the - // AuthToken. + // Contains the AuthToken for the device management server. std::string auth_token_; + // Device identifier to send to the server. + std::string device_id_; + + // Task that has been scheduled to retry fetching a token. + CancelableTask* retry_task_; - // An event that is signaled only once the device token has been fetched - // or it has been determined that there was an error during fetching. - base::WaitableEvent device_token_load_complete_event_; + ScopedRunnableMethodFactory<DeviceTokenFetcher> method_factory_; - // Registers the fetcher for notification of successful Gaia logins. - NotificationRegistrar registrar_; + ObserverList<Observer, true> observer_list_; }; } // namespace policy diff --git a/chrome/browser/policy/device_token_fetcher_unittest.cc b/chrome/browser/policy/device_token_fetcher_unittest.cc index 28d11b0..f87265d 100644 --- a/chrome/browser/policy/device_token_fetcher_unittest.cc +++ b/chrome/browser/policy/device_token_fetcher_unittest.cc @@ -1,18 +1,18 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <string> +#include "chrome/browser/policy/device_token_fetcher.h" #include "base/file_util.h" #include "base/message_loop.h" #include "base/scoped_temp_dir.h" #include "chrome/browser/browser_thread.h" #include "chrome/browser/net/gaia/token_service.h" -#include "chrome/browser/policy/device_token_fetcher.h" +#include "chrome/browser/policy/cloud_policy_cache.h" +#include "chrome/browser/policy/device_management_service.h" #include "chrome/browser/policy/mock_device_management_backend.h" #include "chrome/common/net/gaia/gaia_constants.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" @@ -29,223 +29,170 @@ class MockTokenAvailableObserver : public DeviceTokenFetcher::Observer { MockTokenAvailableObserver() {} virtual ~MockTokenAvailableObserver() {} - MOCK_METHOD0(OnTokenSuccess, void()); - MOCK_METHOD0(OnTokenError, void()); - MOCK_METHOD0(OnNotManaged, void()); + MOCK_METHOD0(OnDeviceTokenAvailable, void()); private: DISALLOW_COPY_AND_ASSIGN(MockTokenAvailableObserver); }; +class MockDeviceManagementService : public DeviceManagementService { + public: + MockDeviceManagementService() + : DeviceManagementService(""), + backend_(NULL) {} + virtual ~MockDeviceManagementService() {} + + void set_backend(DeviceManagementBackend* backend) { + backend_ = backend; + } + virtual DeviceManagementBackend* CreateBackend(); + + private: + DeviceManagementBackend* backend_; // weak + DISALLOW_COPY_AND_ASSIGN(MockDeviceManagementService); +}; + +// This proxy class is used so that expectations can be defined for a single +// persistant instance of DMBackend while the DeviceTokenFetcher under test +// merrily creates and destroys proxies. +class ProxyDeviceManagementBackend : public DeviceManagementBackend { + public: + explicit ProxyDeviceManagementBackend(DeviceManagementBackend* backend) + : backend_(backend) { + } + virtual ~ProxyDeviceManagementBackend() {} + + virtual void ProcessRegisterRequest( + const std::string& auth_token, + const std::string& device_id, + const em::DeviceRegisterRequest& request, + DeviceRegisterResponseDelegate* delegate) { + backend_->ProcessRegisterRequest(auth_token, device_id, request, delegate); + } + virtual void ProcessUnregisterRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::DeviceUnregisterRequest& request, + DeviceUnregisterResponseDelegate* delegate) { + backend_->ProcessUnregisterRequest(device_management_token, device_id, + request, delegate); + } + virtual void ProcessPolicyRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::DevicePolicyRequest& request, + DevicePolicyResponseDelegate* delegate) { + backend_->ProcessPolicyRequest(device_management_token, device_id, + request, delegate); + } + virtual void ProcessCloudPolicyRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::CloudPolicyRequest& request, + DevicePolicyResponseDelegate* delegate) { + backend_->ProcessCloudPolicyRequest(device_management_token, device_id, + request, delegate); + } + + private: + DeviceManagementBackend* backend_; // weak + DISALLOW_COPY_AND_ASSIGN(ProxyDeviceManagementBackend); +}; + +DeviceManagementBackend* + MockDeviceManagementService::CreateBackend() { + return new ProxyDeviceManagementBackend(backend_); +} + class DeviceTokenFetcherTest : public testing::Test { protected: DeviceTokenFetcherTest() : ui_thread_(BrowserThread::UI, &loop_), file_thread_(BrowserThread::FILE, &loop_) { EXPECT_TRUE(temp_user_data_dir_.CreateUniqueTempDir()); - fetcher_ = NewTestFetcher(temp_user_data_dir_.path()); - fetcher_->StartFetching(); } - virtual void TearDown() { - backend_.reset(); - profile_.reset(); - loop_.RunAllPending(); + virtual void SetUp() { + cache_.reset(new CloudPolicyCache( + temp_user_data_dir_.path().AppendASCII("DeviceTokenFetcherTest"))); + service_.set_backend(&backend_); } - void SimulateSuccessfulLoginAndRunPending(const std::string& username) { - loop_.RunAllPending(); - profile_->GetTokenService()->IssueAuthTokenForTest( - GaiaConstants::kDeviceManagementService, kTestToken); - fetcher_->SimulateLogin(username); + virtual void TearDown() { loop_.RunAllPending(); } - TestingDeviceTokenFetcher* NewTestFetcher(const FilePath& token_dir) { - profile_.reset(new TestingProfile()); - backend_.reset(new MockDeviceManagementBackend()); - return new TestingDeviceTokenFetcher( - backend_.get(), - profile_.get(), - token_dir.Append(FILE_PATH_LITERAL("test-token-file.txt"))); - } - - static void GetDeviceTokenPath(const DeviceTokenFetcher* fetcher, - FilePath* path) { - fetcher->GetDeviceTokenPath(path); - } - - const std::string& device_id(const DeviceTokenFetcher* fetcher) { - return fetcher->device_id_; - } - MessageLoop loop_; - scoped_ptr<MockDeviceManagementBackend> backend_; + MockDeviceManagementBackend backend_; + MockDeviceManagementService service_; + scoped_ptr<CloudPolicyCache> cache_; ScopedTempDir temp_user_data_dir_; - scoped_refptr<TestingDeviceTokenFetcher> fetcher_; - scoped_ptr<Profile> profile_; private: BrowserThread ui_thread_; BrowserThread file_thread_; }; -TEST_F(DeviceTokenFetcherTest, IsPending) { - ASSERT_TRUE(fetcher_->IsTokenPending()); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( +TEST_F(DeviceTokenFetcherTest, FetchToken) { + testing::InSequence s; + EXPECT_CALL(backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - SimulateSuccessfulLoginAndRunPending(kTestManagedDomainUsername); - ASSERT_FALSE(fetcher_->IsTokenPending()); -} - -TEST_F(DeviceTokenFetcherTest, StoreAndLoad) { - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - SimulateSuccessfulLoginAndRunPending(kTestManagedDomainUsername); - ASSERT_FALSE(fetcher_->IsTokenPending()); - std::string device_token = fetcher_->GetDeviceToken(); - std::string device_id = fetcher_->GetDeviceID(); - ASSERT_NE("", device_id); - - FilePath token_path; - GetDeviceTokenPath(fetcher_, &token_path); - scoped_refptr<DeviceTokenFetcher> fetcher2( - new TestingDeviceTokenFetcher( - backend_.get(), profile_.get(), token_path)); - fetcher2->StartFetching(); + DeviceTokenFetcher fetcher(&service_, cache_.get()); + MockTokenAvailableObserver observer; + EXPECT_CALL(observer, OnDeviceTokenAvailable()); + fetcher.AddObserver(&observer); + EXPECT_EQ("", fetcher.GetDeviceToken()); + fetcher.FetchToken("fake_auth_token", "fake_device_id"); loop_.RunAllPending(); - ASSERT_EQ(device_id, fetcher2->GetDeviceID()); - ASSERT_EQ(device_token, fetcher2->GetDeviceToken()); -} - -TEST_F(DeviceTokenFetcherTest, SimpleFetchSingleLogin) { - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - SimulateSuccessfulLoginAndRunPending(kTestManagedDomainUsername); - ASSERT_FALSE(fetcher_->IsTokenPending()); - ASSERT_TRUE(fetcher_->IsTokenValid()); - const std::string token(fetcher_->GetDeviceToken()); - EXPECT_NE("", token); -} - -TEST_F(DeviceTokenFetcherTest, SimpleFetchDoubleLogin) { - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - SimulateSuccessfulLoginAndRunPending(kTestManagedDomainUsername); - ASSERT_FALSE(fetcher_->IsTokenPending()); - const std::string token(fetcher_->GetDeviceToken()); + Mock::VerifyAndClearExpectations(&observer); + std::string token = fetcher.GetDeviceToken(); EXPECT_NE("", token); - SimulateSuccessfulLoginAndRunPending(kTestManagedDomainUsername); - ASSERT_FALSE(fetcher_->IsTokenPending()); - const std::string token2(fetcher_->GetDeviceToken()); - EXPECT_NE("", token2); - EXPECT_EQ(token, token2); -} - -TEST_F(DeviceTokenFetcherTest, FetchBetweenBrowserLaunchAndNotify) { - MockTokenAvailableObserver observer; - DeviceTokenFetcher::ObserverRegistrar registrar; - registrar.Init(fetcher_); - registrar.AddObserver(&observer); - EXPECT_CALL(observer, OnTokenSuccess()).Times(1); - EXPECT_CALL(observer, OnTokenError()).Times(0); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( + // Calling FetchToken() again should result in a new token being fetched. + EXPECT_CALL(backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - SimulateSuccessfulLoginAndRunPending(kTestManagedDomainUsername); - ASSERT_FALSE(fetcher_->IsTokenPending()); - const std::string token(fetcher_->GetDeviceToken()); - EXPECT_NE("", token); - Mock::VerifyAndClearExpectations(&observer); - - // Swap out the fetchers, including copying the device management token on - // disk to where the new fetcher expects it. - registrar.RemoveAll(); - fetcher_ = NewTestFetcher(temp_user_data_dir_.path()); - registrar.Init(fetcher_); - fetcher_->StartFetching(); - ASSERT_TRUE(fetcher_->IsTokenPending()); + EXPECT_CALL(observer, OnDeviceTokenAvailable()); + fetcher.FetchToken("fake_auth_token", "fake_device_id"); loop_.RunAllPending(); - ASSERT_FALSE(fetcher_->IsTokenPending()); - const std::string token2(fetcher_->GetDeviceToken()); + Mock::VerifyAndClearExpectations(&observer); + std::string token2 = fetcher.GetDeviceToken(); EXPECT_NE("", token2); - EXPECT_EQ(token, token2); + EXPECT_NE(token, token2); + fetcher.RemoveObserver(&observer); } -TEST_F(DeviceTokenFetcherTest, FailedServerRequest) { - MockTokenAvailableObserver observer; - DeviceTokenFetcher::ObserverRegistrar registrar; - registrar.Init(fetcher_); - registrar.AddObserver(&observer); - EXPECT_CALL(observer, OnTokenSuccess()).Times(0); - EXPECT_CALL(observer, OnTokenError()).Times(1); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( +TEST_F(DeviceTokenFetcherTest, RetryOnError) { + testing::InSequence s; + EXPECT_CALL(backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailRegister( - DeviceManagementBackend::kErrorRequestFailed)); - SimulateSuccessfulLoginAndRunPending(kTestManagedDomainUsername); - ASSERT_FALSE(fetcher_->IsTokenPending()); - const std::string token(fetcher_->GetDeviceToken()); - EXPECT_EQ("", token); + DeviceManagementBackend::kErrorRequestFailed)).WillOnce( + MockDeviceManagementBackendSucceedRegister()); + DeviceTokenFetcher fetcher(&service_, cache_.get(), 0, 0); + MockTokenAvailableObserver observer; + EXPECT_CALL(observer, OnDeviceTokenAvailable()); + fetcher.AddObserver(&observer); + fetcher.FetchToken("fake_auth_token", "fake_device_id"); + loop_.RunAllPending(); + Mock::VerifyAndClearExpectations(&observer); + EXPECT_NE("", fetcher.GetDeviceToken()); + fetcher.RemoveObserver(&observer); } TEST_F(DeviceTokenFetcherTest, UnmanagedDevice) { - FilePath token_path; - GetDeviceTokenPath(fetcher_, &token_path); - file_util::WriteFile(token_path, "foo", 3); - ASSERT_TRUE(file_util::PathExists(token_path)); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailRegister( DeviceManagementBackend::kErrorServiceManagementNotSupported)); - SimulateSuccessfulLoginAndRunPending(kTestManagedDomainUsername); - ASSERT_FALSE(fetcher_->IsTokenPending()); - ASSERT_EQ("", fetcher_->GetDeviceToken()); - ASSERT_EQ("", device_id(fetcher_)); - ASSERT_FALSE(file_util::PathExists(token_path)); -} - - -TEST_F(DeviceTokenFetcherTest, FetchBetweenTokenNotifyAndLoginNotify) { - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).Times(0); - - // Simulate an available token, but without available user name. - loop_.RunAllPending(); - profile_->GetTokenService()->IssueAuthTokenForTest( - GaiaConstants::kDeviceManagementService, kTestToken); - loop_.RunAllPending(); - - ASSERT_TRUE(fetcher_->IsTokenPending()); - ASSERT_FALSE(fetcher_->IsTokenValid()); -} - -TEST_F(DeviceTokenFetcherTest, FetchWithNonManagedUsername) { - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).Times(0); - SimulateSuccessfulLoginAndRunPending("___@gmail.com"); - ASSERT_FALSE(fetcher_->IsTokenPending()); - ASSERT_FALSE(fetcher_->IsTokenValid()); -} - -TEST_F(DeviceTokenFetcherTest, RestartImmediately) { - // Create a token. - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - SimulateSuccessfulLoginAndRunPending(kTestManagedDomainUsername); - ASSERT_FALSE(fetcher_->IsTokenPending()); - std::string device_token = fetcher_->GetDeviceToken(); - - // Restart a new fetcher immediately without calling StartFetching(). The - // existing token should not be loaded, but rather a new token generated. - FilePath token_path; - GetDeviceTokenPath(fetcher_, &token_path); - scoped_refptr<TestingDeviceTokenFetcher> fetcher2( - new TestingDeviceTokenFetcher( - backend_.get(), profile_.get(), token_path)); - fetcher2->Restart(); - EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( - MockDeviceManagementBackendSucceedRegister()); - fetcher2->SimulateLogin(kTestManagedDomainUsername); + EXPECT_FALSE(cache_->is_unmanaged()); + DeviceTokenFetcher fetcher(&service_, cache_.get()); + MockTokenAvailableObserver observer; + EXPECT_CALL(observer, OnDeviceTokenAvailable()).Times(0); + fetcher.AddObserver(&observer); + fetcher.FetchToken("fake_auth_token", "fake_device_id"); loop_.RunAllPending(); - ASSERT_FALSE(fetcher2->IsTokenPending()); - ASSERT_NE(device_token, fetcher2->GetDeviceToken()); + Mock::VerifyAndClearExpectations(&observer); + EXPECT_EQ("", fetcher.GetDeviceToken()); + EXPECT_TRUE(cache_->is_unmanaged()); + fetcher.RemoveObserver(&observer); } } // namespace policy diff --git a/chrome/browser/policy/profile_policy_connector.cc b/chrome/browser/policy/profile_policy_connector.cc new file mode 100644 index 0000000..ac22603 --- /dev/null +++ b/chrome/browser/policy/profile_policy_connector.cc @@ -0,0 +1,100 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <algorithm> +#include <string> + +#include "base/command_line.h" +#include "base/file_util.h" +#include "chrome/browser/policy/cloud_policy_subsystem.h" +#include "chrome/browser/policy/profile_policy_connector.h" +#include "chrome/browser/policy/user_policy_identity_strategy.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/net/url_request_context_getter.h" +#include "chrome/common/pref_names.h" + +namespace { + +const FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Device Management"); +const FilePath::CharType kTokenCacheFile[] = FILE_PATH_LITERAL("Token"); +const FilePath::CharType kPolicyCacheFile[] = FILE_PATH_LITERAL("Policy"); + +} // namespace + +namespace policy { + +ProfilePolicyConnector::ProfilePolicyConnector(Profile* profile) + : profile_(profile) { + // TODO(mnissler): We access the file system here. The cloud policy context + // below needs to do so anyway, since it needs to read the policy cache from + // disk. If this proves to be a problem, we need to do this initialization + // asynchronously on the file thread and put in synchronization that allows us + // to wait for the cache to be read during the browser startup code paths. + // Another option would be to provide a generic IO-safe initializer called + // from the PrefService that we could hook up with through the policy + // provider. + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kDeviceManagementUrl)) { + FilePath policy_cache_dir(profile_->GetPath()); + policy_cache_dir = policy_cache_dir.Append(kPolicyDir); + if (!file_util::CreateDirectory(policy_cache_dir)) { + LOG(WARNING) << "Failed to create policy state dir " + << policy_cache_dir.value() + << ", skipping cloud policy initialization."; + return; + } + + identity_strategy_.reset(new UserPolicyIdentityStrategy( + profile_, + policy_cache_dir.Append(kTokenCacheFile))); + cloud_policy_subsystem_.reset(new CloudPolicySubsystem( + policy_cache_dir.Append(kPolicyCacheFile), + identity_strategy_.get())); + } +} + +ProfilePolicyConnector::~ProfilePolicyConnector() { + cloud_policy_subsystem_.reset(); + identity_strategy_.reset(); +} + +void ProfilePolicyConnector::Initialize() { + // TODO(jkummerow, mnissler): Move this out of the browser startup path. + if (cloud_policy_subsystem_.get()) { + cloud_policy_subsystem_->Initialize(profile_->GetPrefs(), + prefs::kPolicyUserPolicyRefreshRate, + profile_->GetRequestContext()); + } +} + +void ProfilePolicyConnector::Shutdown() { + if (cloud_policy_subsystem_.get()) + cloud_policy_subsystem_->Shutdown(); +} + +ConfigurationPolicyProvider* + ProfilePolicyConnector::GetManagedCloudProvider() { + if (cloud_policy_subsystem_.get()) + return cloud_policy_subsystem_->GetManagedPolicyProvider(); + + return NULL; +} + +ConfigurationPolicyProvider* + ProfilePolicyConnector::GetRecommendedCloudProvider() { + if (cloud_policy_subsystem_.get()) + return cloud_policy_subsystem_->GetRecommendedPolicyProvider(); + + return NULL; +} + +// static +void ProfilePolicyConnector::RegisterPrefs(PrefService* user_prefs) { + user_prefs->RegisterIntegerPref(prefs::kPolicyUserPolicyRefreshRate, + kDefaultPolicyRefreshRateInMilliseconds); +} + +} // namespace policy diff --git a/chrome/browser/policy/profile_policy_connector.h b/chrome/browser/policy/profile_policy_connector.h new file mode 100644 index 0000000..f65d077 --- /dev/null +++ b/chrome/browser/policy/profile_policy_connector.h @@ -0,0 +1,56 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_PROFILE_POLICY_CONNECTOR_H_ +#define CHROME_BROWSER_POLICY_PROFILE_POLICY_CONNECTOR_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" + +class Profile; + +namespace policy { + +class CloudPolicySubsystem; +class ConfigurationPolicyProvider; +class UserPolicyIdentityStrategy; + +// This class is a container for the profile-specific policy bits located in the +// profile. Since the subsystem owns the policy provider, it's vital that it +// gets initialized before the profile's prefs and destroyed after the prefs +// are gone. +class ProfilePolicyConnector { + public: + explicit ProfilePolicyConnector(Profile* profile); + ~ProfilePolicyConnector(); + + // Initializes the context. Should be called only after the profile's request + // context is up. + void Initialize(); + + // Shuts the context down. This must be called before the networking + // infrastructure in the profile goes away. + void Shutdown(); + + ConfigurationPolicyProvider* GetManagedCloudProvider(); + ConfigurationPolicyProvider* GetRecommendedCloudProvider(); + + static void RegisterPrefs(PrefService* user_prefs); + + static const int kDefaultPolicyRefreshRateInMilliseconds = + 3 * 60 * 60 * 1000; // 3 hours. + + private: + Profile* profile_; + + scoped_ptr<UserPolicyIdentityStrategy> identity_strategy_; + scoped_ptr<CloudPolicySubsystem> cloud_policy_subsystem_; + + DISALLOW_COPY_AND_ASSIGN(ProfilePolicyConnector); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_PROFILE_POLICY_CONNECTOR_H_ diff --git a/chrome/browser/policy/profile_policy_context.cc b/chrome/browser/policy/profile_policy_context.cc deleted file mode 100644 index b8e3151a..0000000 --- a/chrome/browser/policy/profile_policy_context.cc +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <algorithm> -#include <string> - -#include "base/command_line.h" -#include "chrome/browser/policy/configuration_policy_pref_store.h" -#include "chrome/browser/policy/device_management_policy_provider.h" -#include "chrome/browser/policy/device_management_service.h" -#include "chrome/browser/policy/profile_policy_context.h" -#include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/notification_details.h" -#include "chrome/common/notification_source.h" -#include "chrome/common/pref_names.h" - -namespace { - -// Refresh rate sanity interval bounds. -const int64 kPolicyRefreshRateMinMs = 30 * 60 * 1000; // 30 minutes -const int64 kPolicyRefreshRateMaxMs = 24 * 60 * 60 * 1000; // 1 day - -} // namespace - -namespace policy { - -ProfilePolicyContext::ProfilePolicyContext(Profile* profile) - : profile_(profile) { - CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kDeviceManagementUrl)) { - device_management_service_.reset(new DeviceManagementService( - command_line->GetSwitchValueASCII(switches::kDeviceManagementUrl))); - device_management_policy_provider_.reset( - new policy::DeviceManagementPolicyProvider( - ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), - device_management_service_->CreateBackend(), - profile_)); - } -} - -ProfilePolicyContext::~ProfilePolicyContext() { - device_management_policy_provider_.reset(); - device_management_service_.reset(); -} - -void ProfilePolicyContext::Initialize() { - if (device_management_service_.get()) - device_management_service_->Initialize(profile_->GetRequestContext()); - - policy_refresh_rate_.Init(prefs::kPolicyRefreshRate, profile_->GetPrefs(), - this); - UpdatePolicyRefreshRate(); -} - -void ProfilePolicyContext::Shutdown() { - if (device_management_service_.get()) - device_management_service_->Shutdown(); -} - -DeviceManagementPolicyProvider* -ProfilePolicyContext::GetDeviceManagementPolicyProvider() { - return device_management_policy_provider_.get(); -} - -// static -void ProfilePolicyContext::RegisterUserPrefs(PrefService* user_prefs) { - user_prefs->RegisterIntegerPref(prefs::kPolicyRefreshRate, - kDefaultPolicyRefreshRateInMilliseconds); -} - -void ProfilePolicyContext::UpdatePolicyRefreshRate() { - if (device_management_policy_provider_.get()) { - // Clamp to sane values. - int64 refresh_rate = policy_refresh_rate_.GetValue(); - refresh_rate = std::max(kPolicyRefreshRateMinMs, refresh_rate); - refresh_rate = std::min(kPolicyRefreshRateMaxMs, refresh_rate); - device_management_policy_provider_->SetRefreshRate(refresh_rate); - } -} - -void ProfilePolicyContext::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - if (type == NotificationType::PREF_CHANGED && - prefs::kPolicyRefreshRate == *(Details<std::string>(details).ptr()) && - profile_->GetPrefs() == Source<PrefService>(source).ptr()) { - UpdatePolicyRefreshRate(); - } else { - NOTREACHED(); - } -} - -} // namespace policy diff --git a/chrome/browser/policy/profile_policy_context.h b/chrome/browser/policy/profile_policy_context.h deleted file mode 100644 index 8650ec5..0000000 --- a/chrome/browser/policy/profile_policy_context.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_POLICY_PROFILE_POLICY_CONTEXT_H_ -#define CHROME_BROWSER_POLICY_PROFILE_POLICY_CONTEXT_H_ -#pragma once - -#include "base/scoped_ptr.h" -#include "chrome/browser/prefs/pref_member.h" -#include "chrome/common/notification_observer.h" - -class Profile; - -namespace policy { - -class DeviceManagementPolicyProvider; -class DeviceManagementService; - -// This class is a container for the profile-specific policy bits located in the -// profile. Since the context owns the policy provider, it's vital that it gets -// initialized before the profile's prefs and destroyed after the prefs are -// gone. -class ProfilePolicyContext : public NotificationObserver { - public: - explicit ProfilePolicyContext(Profile* profile); - ~ProfilePolicyContext(); - - // Initializes the context. Should be called only after the profile's request - // context is up. - void Initialize(); - - // Shuts the context down. This must be called before the networking - // infrastructure in the profile goes away. - void Shutdown(); - - // Get the policy provider. - DeviceManagementPolicyProvider* GetDeviceManagementPolicyProvider(); - - // Register preferences. - static void RegisterUserPrefs(PrefService* user_prefs); - - static const int kDefaultPolicyRefreshRateInMilliseconds = - 3 * 60 * 60 * 1000; // 3 hours. - - private: - // Updates the policy provider with a new refresh rate value. - void UpdatePolicyRefreshRate(); - - // NotificationObserver overrides. - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - - // The profile this context is associated with. - Profile* profile_; - - // Tracks the pref value for the policy refresh rate. - IntegerPrefMember policy_refresh_rate_; - - // The device management service. - scoped_ptr<DeviceManagementService> device_management_service_; - - // Our provider. - scoped_ptr<DeviceManagementPolicyProvider> device_management_policy_provider_; -}; - -} // namespace policy - -#endif // CHROME_BROWSER_POLICY_PROFILE_POLICY_CONTEXT_H_ diff --git a/chrome/browser/policy/user_policy_identity_strategy.cc b/chrome/browser/policy/user_policy_identity_strategy.cc new file mode 100644 index 0000000..5270ca3 --- /dev/null +++ b/chrome/browser/policy/user_policy_identity_strategy.cc @@ -0,0 +1,236 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/user_policy_identity_strategy.h" + +#include "base/file_util.h" +#include "chrome/browser/browser_signin.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/net/gaia/token_service.h" +#include "chrome/browser/policy/proto/device_management_local.pb.h" +#include "chrome/browser/profiles/profile.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" +#include "chrome/common/notification_source.h" + +namespace policy { + +namespace em = enterprise_management; + +// Responsible for managing the on-disk token cache. +class UserPolicyIdentityStrategy::TokenCache + : public base::RefCountedThreadSafe< + UserPolicyIdentityStrategy::TokenCache> { + public: + TokenCache(const base::WeakPtr<UserPolicyIdentityStrategy>& identity_strategy, + const FilePath& cache_file); + + void Load(); + void Store(const std::string& token, const std::string& device_id); + + private: + friend class base::RefCountedThreadSafe< + UserPolicyIdentityStrategy::TokenCache>; + ~TokenCache() {} + void LoadOnFileThread(); + void NotifyOnUIThread(const std::string& token, + const std::string& device_id); + void StoreOnFileThread(const std::string& token, + const std::string& device_id); + + const base::WeakPtr<UserPolicyIdentityStrategy> identity_strategy_; + const FilePath cache_file_; + + DISALLOW_COPY_AND_ASSIGN(TokenCache); +}; + +UserPolicyIdentityStrategy::TokenCache::TokenCache( + const base::WeakPtr<UserPolicyIdentityStrategy>& identity_strategy, + const FilePath& cache_file) + : identity_strategy_(identity_strategy), + cache_file_(cache_file) {} + +void UserPolicyIdentityStrategy::TokenCache::Load() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod( + this, &UserPolicyIdentityStrategy::TokenCache::LoadOnFileThread)); +} + +void UserPolicyIdentityStrategy::TokenCache::Store( + const std::string& token, + const std::string& device_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod( + this, + &UserPolicyIdentityStrategy::TokenCache::StoreOnFileThread, + token, + device_id)); +} + +void UserPolicyIdentityStrategy::TokenCache::LoadOnFileThread() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + std::string device_token; + std::string device_id; + + if (file_util::PathExists(cache_file_)) { + std::string data; + em::DeviceCredentials device_credentials; + if (file_util::ReadFileToString(cache_file_, &data) && + device_credentials.ParseFromArray(data.c_str(), data.size())) { + device_token = device_credentials.device_token(); + device_id = device_credentials.device_id(); + } + } + + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod( + this, + &UserPolicyIdentityStrategy::TokenCache::NotifyOnUIThread, + device_token, + device_id)); +} + +void UserPolicyIdentityStrategy::TokenCache::NotifyOnUIThread( + const std::string& token, + const std::string& device_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (identity_strategy_.get()) + identity_strategy_->OnCacheLoaded(token, device_id); +} + +void UserPolicyIdentityStrategy::TokenCache::StoreOnFileThread( + const std::string& token, + const std::string& device_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + em::DeviceCredentials device_credentials; + device_credentials.set_device_token(token); + device_credentials.set_device_id(device_id); + std::string data; + bool success = device_credentials.SerializeToString(&data); + if (!success) { + LOG(WARNING) << "Failed serialize device token data, will not write " + << cache_file_.value(); + return; + } + + file_util::WriteFile(cache_file_, data.c_str(), data.length()); +} + +UserPolicyIdentityStrategy::UserPolicyIdentityStrategy( + Profile* profile, + const FilePath& cache_file) + : profile_(profile), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { + cache_ = new TokenCache(weak_ptr_factory_.GetWeakPtr(), cache_file); + registrar_.Add(this, + NotificationType::TOKEN_AVAILABLE, + Source<TokenService>(profile->GetTokenService())); + + // Register for the event of user login. The device management token won't + // be fetched until we know the domain of the currently logged in user. +#if defined(OS_CHROMEOS) + registrar_.Add(this, + NotificationType::LOGIN_USER_CHANGED, + NotificationService::AllSources()); +#else + registrar_.Add(this, + NotificationType::GOOGLE_SIGNIN_SUCCESSFUL, + Source<Profile>(profile_)); +#endif + + cache_->Load(); +} + +UserPolicyIdentityStrategy::~UserPolicyIdentityStrategy() {} + +std::string UserPolicyIdentityStrategy::GetDeviceToken() { + return device_token_; +} + +std::string UserPolicyIdentityStrategy::GetDeviceID() { + return device_id_; +} + +bool UserPolicyIdentityStrategy::GetCredentials(std::string* username, + std::string* auth_token) { + *username = GetCurrentUser(); + *auth_token = profile_->GetTokenService()->GetTokenForService( + GaiaConstants::kDeviceManagementService); + + return !username->empty() && !auth_token->empty() && !device_id_.empty(); +} + +void UserPolicyIdentityStrategy::OnDeviceTokenAvailable( + const std::string& token) { + DCHECK(!device_id_.empty()); + device_token_ = token; + cache_->Store(device_token_, device_id_); + NotifyDeviceTokenChanged(); +} + +std::string UserPolicyIdentityStrategy::GetCurrentUser() { +#if defined(OS_CHROMEOS) + // TODO(mnissler) On CrOS it seems impossible to figure out what user belongs + // to a profile. Revisit after multi-profile support landed. + return chromeos::UserManager::Get()->logged_in_user().email(); +#else + return profile_->GetBrowserSignin()->GetSignedInUsername(); +#endif +} + +void UserPolicyIdentityStrategy::CheckAndTriggerFetch() { + if (!GetCurrentUser().empty() && + profile_->GetTokenService()->HasTokenForService( + GaiaConstants::kDeviceManagementService)) { + // For user tokens, there is no actual identifier. We generate a random + // identifier instead each time we ask for the token. + device_id_ = guid::GenerateGUID(); + NotifyAuthChanged(); + } +} + +void UserPolicyIdentityStrategy::OnCacheLoaded(const std::string& token, + const std::string& device_id) { + if (!token.empty() && !device_id.empty()) { + device_token_ = token; + device_id_ = device_id; + NotifyDeviceTokenChanged(); + } else { + CheckAndTriggerFetch(); + } +} + +void UserPolicyIdentityStrategy::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (type == NotificationType::TOKEN_AVAILABLE) { + if (Source<TokenService>(source).ptr() == profile_->GetTokenService()) { + const TokenService::TokenAvailableDetails* token_details = + Details<const TokenService::TokenAvailableDetails>(details).ptr(); + if (token_details->service() == GaiaConstants::kDeviceManagementService) + CheckAndTriggerFetch(); + } +#if defined(OS_CHROMEOS) + } else if (type == NotificationType::LOGIN_USER_CHANGED) { + CheckAndTriggerFetch(); +#else + } else if (type == NotificationType::GOOGLE_SIGNIN_SUCCESSFUL) { + if (profile_ == Source<Profile>(source).ptr()) + CheckAndTriggerFetch(); +#endif + } else { + NOTREACHED(); + } +} + +} // namespace policy diff --git a/chrome/browser/policy/user_policy_identity_strategy.h b/chrome/browser/policy/user_policy_identity_strategy.h new file mode 100644 index 0000000..bf6ca55 --- /dev/null +++ b/chrome/browser/policy/user_policy_identity_strategy.h @@ -0,0 +1,81 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_USER_POLICY_IDENTITY_STRATEGY_H_ +#define CHROME_BROWSER_POLICY_USER_POLICY_IDENTITY_STRATEGY_H_ +#pragma once + +#include <string> + +#include "base/file_path.h" +#include "base/ref_counted.h" +#include "base/weak_ptr.h" +#include "chrome/browser/policy/cloud_policy_identity_strategy.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" + +class Profile; + +namespace policy { + +class DeviceManagementBackend; + +// A token provider implementation that provides a user device token for the +// user corresponding to a given profile. +class UserPolicyIdentityStrategy : public CloudPolicyIdentityStrategy, + public NotificationObserver { + public: + UserPolicyIdentityStrategy(Profile* profile, + const FilePath& token_cache_file); + virtual ~UserPolicyIdentityStrategy(); + + // CloudPolicyIdentityStrategy implementation: + virtual std::string GetDeviceToken(); + virtual std::string GetDeviceID(); + virtual bool GetCredentials(std::string* username, + std::string* auth_token); + virtual void OnDeviceTokenAvailable(const std::string& token); + + private: + class TokenCache; + + // Checks whether a new token should be fetched and if so, sends out a + // notification. + void CheckAndTriggerFetch(); + + // Gets the current user. + std::string GetCurrentUser(); + + // Called from the token cache when the token has been loaded. + void OnCacheLoaded(const std::string& token, const std::string& device_id); + + // NotificationObserver method overrides: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // The profile this provider is associated with. + Profile* profile_; + + // Keeps the on-disk copy of the token. + scoped_refptr<TokenCache> cache_; + + // The device ID we use. + std::string device_id_; + + // Current device token. Empty if not available. + std::string device_token_; + + // Registers the provider for notification of successful Gaia logins. + NotificationRegistrar registrar_; + + // Allows to construct weak ptrs. + base::WeakPtrFactory<UserPolicyIdentityStrategy> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(UserPolicyIdentityStrategy); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_USER_POLICY_IDENTITY_STRATEGY_H_ diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 0c76b2f..a03452f 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc @@ -34,7 +34,8 @@ #include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/browser/page_info_model.h" #include "chrome/browser/password_manager/password_manager.h" -#include "chrome/browser/policy/profile_policy_context.h" +#include "chrome/browser/policy/browser_policy_connector.h" +#include "chrome/browser/policy/profile_policy_connector.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile_impl.h" #include "chrome/browser/renderer_host/browser_render_process_host.h" @@ -101,6 +102,7 @@ void RegisterLocalState(PrefService* local_state) { BackgroundPageTracker::RegisterPrefs(local_state); NotificationUIManager::RegisterPrefs(local_state); PrefProxyConfigService::RegisterPrefs(local_state); + policy::BrowserPolicyConnector::RegisterPrefs(local_state); #if defined(OS_CHROMEOS) chromeos::AudioMixerAlsa::RegisterPrefs(local_state); chromeos::UserManager::RegisterPrefs(local_state); @@ -150,7 +152,7 @@ void RegisterUserPrefs(PrefService* user_prefs) { TemplateURLModel::RegisterUserPrefs(user_prefs); InstantController::RegisterUserPrefs(user_prefs); NetPrefObserver::RegisterPrefs(user_prefs); - policy::ProfilePolicyContext::RegisterUserPrefs(user_prefs); + policy::ProfilePolicyConnector::RegisterPrefs(user_prefs); ProtocolHandlerRegistry::RegisterPrefs(user_prefs); } diff --git a/chrome/browser/prefs/pref_member.h b/chrome/browser/prefs/pref_member.h index 977e1f1..1884edc 100644 --- a/chrome/browser/prefs/pref_member.h +++ b/chrome/browser/prefs/pref_member.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -192,6 +192,11 @@ class PrefMember : public subtle::PrefMemberBase { } } + // Returns the pref name. + const std::string& GetPrefName() const { + return pref_name(); + } + private: class Internal : public subtle::PrefMemberBase::Internal { public: diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc index 0443d9c..f183856 100644 --- a/chrome/browser/profiles/profile.cc +++ b/chrome/browser/profiles/profile.cc @@ -640,7 +640,7 @@ class OffTheRecordProfileImpl : public Profile, return profile_->GetExtensionInfoMap(); } - virtual policy::ProfilePolicyContext* GetPolicyContext() { + virtual policy::ProfilePolicyConnector* GetPolicyConnector() { return NULL; } diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h index 71eaf25..42252da 100644 --- a/chrome/browser/profiles/profile.h +++ b/chrome/browser/profiles/profile.h @@ -37,7 +37,7 @@ class SSLConfigService; } namespace policy { -class ProfilePolicyContext; +class ProfilePolicyConnector; } namespace prerender { @@ -505,8 +505,8 @@ class Profile { // Returns the PromoCounter for Instant, or NULL if not applicable. virtual PromoCounter* GetInstantPromoCounter() = 0; - // Gets the policy context associated with this profile. - virtual policy::ProfilePolicyContext* GetPolicyContext() = 0; + // Gets the policy connector associated with this profile. + virtual policy::ProfilePolicyConnector* GetPolicyConnector() = 0; // Returns the ChromeURLDataManager for this profile. virtual ChromeURLDataManager* GetChromeURLDataManager() = 0; diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 54f58db..91db2cd 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc @@ -58,7 +58,7 @@ #include "chrome/browser/password_manager/password_store_default.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/configuration_policy_provider.h" -#include "chrome/browser/policy/profile_policy_context.h" +#include "chrome/browser/policy/profile_policy_connector.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/prefs/pref_value_store.h" #include "chrome/browser/prerender/prerender_manager.h" @@ -345,9 +345,9 @@ ProfileImpl::ProfileImpl(const FilePath& path) io_data_.Init(cookie_path, cache_path, cache_max_size, media_cache_path, media_cache_max_size, extensions_cookie_path); - // Initialize the ProfilePolicyContext after |io_data_| since it requires + // Initialize the ProfilePolicyConnector after |io_data_| since it requires // the URLRequestContextGetter to be initialized. - GetPolicyContext()->Initialize(); + GetPolicyConnector()->Initialize(); } void ProfileImpl::InitExtensions() { @@ -519,7 +519,7 @@ ProfileImpl::~ProfileImpl() { Source<Profile>(this), NotificationService::NoDetails()); - GetPolicyContext()->Shutdown(); + GetPolicyConnector()->Shutdown(); tab_restore_service_ = NULL; @@ -1380,11 +1380,11 @@ ExtensionInfoMap* ProfileImpl::GetExtensionInfoMap() { return extension_info_map_.get(); } -policy::ProfilePolicyContext* ProfileImpl::GetPolicyContext() { - if (!profile_policy_context_.get()) - profile_policy_context_.reset(new policy::ProfilePolicyContext(this)); +policy::ProfilePolicyConnector* ProfileImpl::GetPolicyConnector() { + if (!profile_policy_connector_.get()) + profile_policy_connector_.reset(new policy::ProfilePolicyConnector(this)); - return profile_policy_context_.get(); + return profile_policy_connector_.get(); } ChromeURLDataManager* ProfileImpl::GetChromeURLDataManager() { diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h index 7cc5e4a..5eea88cb 100644 --- a/chrome/browser/profiles/profile_impl.h +++ b/chrome/browser/profiles/profile_impl.h @@ -132,7 +132,7 @@ class ProfileImpl : public Profile, virtual ExtensionInfoMap* GetExtensionInfoMap(); virtual PromoCounter* GetInstantPromoCounter(); virtual BrowserSignin* GetBrowserSignin(); - virtual policy::ProfilePolicyContext* GetPolicyContext(); + virtual policy::ProfilePolicyConnector* GetPolicyConnector(); virtual ChromeURLDataManager* GetChromeURLDataManager(); #if defined(OS_CHROMEOS) @@ -206,7 +206,7 @@ class ProfileImpl : public Profile, transport_security_state_; scoped_refptr<TransportSecurityPersister> transport_security_persister_; - scoped_ptr<policy::ProfilePolicyContext> profile_policy_context_; + scoped_ptr<policy::ProfilePolicyConnector> profile_policy_connector_; scoped_ptr<NetPrefObserver> net_pref_observer_; scoped_ptr<TemplateURLFetcher> template_url_fetcher_; scoped_ptr<TemplateURLModel> template_url_model_; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index d17c616..ac188c6 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1594,8 +1594,15 @@ 'browser/policy/asynchronous_policy_loader.h', 'browser/policy/asynchronous_policy_provider.cc', 'browser/policy/asynchronous_policy_provider.h', + 'browser/policy/browser_policy_connector.cc', + 'browser/policy/browser_policy_connector.h', 'browser/policy/cloud_policy_cache.cc', 'browser/policy/cloud_policy_cache.h', + 'browser/policy/cloud_policy_controller.cc', + 'browser/policy/cloud_policy_controller.h', + 'browser/policy/cloud_policy_identity_strategy.h', + 'browser/policy/cloud_policy_subsystem.cc', + 'browser/policy/cloud_policy_subsystem.h', 'browser/policy/config_dir_policy_provider.cc', 'browser/policy/config_dir_policy_provider.h', 'browser/policy/configuration_policy_loader_win.cc', @@ -1606,8 +1613,6 @@ 'browser/policy/configuration_policy_provider.h', 'browser/policy/configuration_policy_provider_delegate_win.cc', 'browser/policy/configuration_policy_provider_delegate_win.h', - 'browser/policy/configuration_policy_provider_keeper.cc', - 'browser/policy/configuration_policy_provider_keeper.h', 'browser/policy/configuration_policy_provider_mac.cc', 'browser/policy/configuration_policy_provider_mac.h', 'browser/policy/configuration_policy_provider_win.cc', @@ -1616,10 +1621,10 @@ 'browser/policy/device_management_backend.h', 'browser/policy/device_management_backend_impl.cc', 'browser/policy/device_management_backend_impl.h', - 'browser/policy/device_management_policy_provider.cc', - 'browser/policy/device_management_policy_provider.h', 'browser/policy/device_management_service.cc', 'browser/policy/device_management_service.h', + 'browser/policy/device_policy_identity_strategy.cc', + 'browser/policy/device_policy_identity_strategy.h', 'browser/policy/device_token_fetcher.cc', 'browser/policy/device_token_fetcher.h', 'browser/policy/dummy_configuration_policy_provider.cc', @@ -1630,8 +1635,10 @@ 'browser/policy/file_based_policy_provider.h', 'browser/policy/managed_prefs_banner_base.cc', 'browser/policy/managed_prefs_banner_base.h', - 'browser/policy/profile_policy_context.cc', - 'browser/policy/profile_policy_context.h', + 'browser/policy/profile_policy_connector.cc', + 'browser/policy/profile_policy_connector.h', + 'browser/policy/user_policy_identity_strategy.cc', + 'browser/policy/user_policy_identity_strategy.h', # TODO(danno): Find a better way to include these files '<(protoc_out_dir)/chrome/browser/policy/proto/device_management_backend.pb.cc', '<(protoc_out_dir)/chrome/browser/policy/proto/device_management_backend.pb.h', @@ -3492,6 +3499,8 @@ ['exclude', 'browser/extensions/extension_tts_api_chromeos.cc'], ['exclude', 'browser/oom_priority_manager.cc'], ['exclude', 'browser/oom_priority_manager.h'], + ['exclude', 'browser/policy/device_policy_identity_strategy.cc'], + ['exclude', 'browser/policy/device_policy_identity_strategy.h'], ['exclude', 'browser/renderer_host/offline_resource_handler.cc'], ['exclude', 'browser/renderer_host/offline_resource_handler.h'], ['exclude', 'browser/webui/filebrowse_ui.cc'], diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 837ab0f..fbdbf3a 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -160,8 +160,6 @@ 'test/testing_browser_process.cc', 'test/testing_browser_process.h', 'test/testing_browser_process_test.h', - 'test/testing_device_token_fetcher.cc', - 'test/testing_device_token_fetcher.h', 'test/testing_pref_service.cc', 'test/testing_pref_service.h', 'test/testing_profile.cc', @@ -1405,6 +1403,7 @@ 'browser/policy/asynchronous_policy_test_base.cc', 'browser/policy/asynchronous_policy_test_base.h', 'browser/policy/cloud_policy_cache_unittest.cc', + 'browser/policy/cloud_policy_controller_unittest.cc', 'browser/policy/config_dir_policy_provider_unittest.cc', 'browser/policy/configuration_policy_pref_store_unittest.cc', 'browser/policy/configuration_policy_provider_mac_unittest.cc', @@ -1414,7 +1413,6 @@ 'browser/policy/device_management_backend_mock.cc', 'browser/policy/device_management_backend_mock.h', 'browser/policy/device_management_service_unittest.cc', - 'browser/policy/device_management_policy_provider_unittest.cc', 'browser/policy/managed_prefs_banner_base_unittest.cc', 'browser/policy/mock_configuration_policy_provider.cc', 'browser/policy/mock_configuration_policy_provider.h', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 62978fc..b3e69ef 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -150,6 +150,10 @@ const char kDebugPrint[] = "debug-print"; // device management backend. const char kDeviceManagementUrl[] = "device-management-url"; +// Specifies the directory in which to store the shared device policy cache +// file. If not specified, device policy will be disabled. +const char kDevicePolicyCacheDir[] = "device-policy-cache-dir"; + // Triggers a pletora of diagnostic modes. const char kDiagnostics[] = "diagnostics"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index a55991b5..faad820 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -9,6 +9,7 @@ #pragma once #include "build/build_config.h" + #include "base/base_switches.h" namespace switches { @@ -54,6 +55,7 @@ extern const char kConflictingModulesCheck[]; extern const char kCountry[]; extern const char kDebugPrint[]; extern const char kDeviceManagementUrl[]; +extern const char kDevicePolicyCacheDir[]; extern const char kDiagnostics[]; extern const char kDisable3DAPIs[]; extern const char kDisableAcceleratedCompositing[]; diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 27b364d..19b74330 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -674,10 +674,14 @@ const char kEnableTranslate[] = "translate.enabled"; const char kPinnedTabs[] = "pinned_tabs"; -// Integer that specifies the policy refresh rate in milliseconds. Not all -// values are meaningful, so it is clamped to a sane range by the policy -// provider. -const char kPolicyRefreshRate[] = "policy.refresh_rate"; +// Integer that specifies the policy refresh rate for user policy in +// milliseconds. Not all values are meaningful, so it is clamped to a sane +// range by the cloud policy subsystem. +const char kPolicyUserPolicyRefreshRate[] = "policy.user_policy_refresh_rate"; + +// Same as |kPolicyUserPolicyRefreshRate|, but for device policy. +const char kPolicyDevicePolicyRefreshRate[] = + "policy.device_policy_refresh_rate"; // Integer containing the default Geolocation content setting. const char kGeolocationDefaultContentSetting[] = diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index f41e3ff..14364d9 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -238,7 +238,9 @@ extern const char kAutoFillPersonalDataManagerFirstRun[]; extern const char kUseVerticalTabs[]; extern const char kEnableTranslate[]; extern const char kPinnedTabs[]; -extern const char kPolicyRefreshRate[]; + +extern const char kPolicyUserPolicyRefreshRate[]; +extern const char kPolicyDevicePolicyRefreshRate[]; // Local state extern const char kMetricsClientID[]; diff --git a/chrome/test/testing_browser_process.cc b/chrome/test/testing_browser_process.cc index 01090d2..e6f5696 100644 --- a/chrome/test/testing_browser_process.cc +++ b/chrome/test/testing_browser_process.cc @@ -8,9 +8,9 @@ #include "base/synchronization/waitable_event.h" #include "chrome/browser/google/google_url_tracker.h" #include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/policy/browser_policy_connector.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" #include "chrome/browser/policy/configuration_policy_provider.h" -#include "chrome/browser/policy/configuration_policy_provider_keeper.h" #include "chrome/browser/policy/dummy_configuration_policy_provider.h" #include "ui/base/clipboard/clipboard.h" @@ -18,8 +18,7 @@ TestingBrowserProcess::TestingBrowserProcess() : shutdown_event_(new base::WaitableEvent(true, false)), module_ref_count_(0), app_locale_("en"), - pref_service_(NULL), - created_configuration_policy_provider_keeper_(false) { + pref_service_(NULL) { } TestingBrowserProcess::~TestingBrowserProcess() { @@ -70,21 +69,18 @@ PrefService* TestingBrowserProcess::local_state() { return pref_service_; } -policy::ConfigurationPolicyProviderKeeper* -TestingBrowserProcess::configuration_policy_provider_keeper() { - if (!created_configuration_policy_provider_keeper_) { - DCHECK(configuration_policy_provider_keeper_.get() == NULL); - created_configuration_policy_provider_keeper_ = true; +policy::BrowserPolicyConnector* + TestingBrowserProcess::browser_policy_connector() { + if (!browser_policy_connector_.get()) { const policy::ConfigurationPolicyProvider::PolicyDefinitionList* policy_list = policy::ConfigurationPolicyPrefStore:: GetChromePolicyDefinitionList(); - configuration_policy_provider_keeper_.reset( - new policy::ConfigurationPolicyProviderKeeper( - new policy::DummyConfigurationPolicyProvider(policy_list), + browser_policy_connector_.reset( + new policy::BrowserPolicyConnector( new policy::DummyConfigurationPolicyProvider(policy_list), new policy::DummyConfigurationPolicyProvider(policy_list))); } - return configuration_policy_provider_keeper_.get(); + return browser_policy_connector_.get(); } IconManager* TestingBrowserProcess::icon_manager() { diff --git a/chrome/test/testing_browser_process.h b/chrome/test/testing_browser_process.h index 04e50939..7ccef97 100644 --- a/chrome/test/testing_browser_process.h +++ b/chrome/test/testing_browser_process.h @@ -29,7 +29,7 @@ class WaitableEvent; } namespace policy { -class ConfigurationPolicyProviderKeeper; +class BrowserPolicyConnector; } namespace ui { @@ -65,8 +65,7 @@ class TestingBrowserProcess : public BrowserProcess { virtual PrefService* local_state(); - virtual policy::ConfigurationPolicyProviderKeeper* - configuration_policy_provider_keeper(); + virtual policy::BrowserPolicyConnector* browser_policy_connector(); virtual IconManager* icon_manager(); @@ -140,9 +139,7 @@ class TestingBrowserProcess : public BrowserProcess { std::string app_locale_; PrefService* pref_service_; - bool created_configuration_policy_provider_keeper_; - scoped_ptr<policy::ConfigurationPolicyProviderKeeper> - configuration_policy_provider_keeper_; + scoped_ptr<policy::BrowserPolicyConnector> browser_policy_connector_; scoped_ptr<GoogleURLTracker> google_url_tracker_; DISALLOW_COPY_AND_ASSIGN(TestingBrowserProcess); diff --git a/chrome/test/testing_device_token_fetcher.cc b/chrome/test/testing_device_token_fetcher.cc deleted file mode 100644 index 263f47a..0000000 --- a/chrome/test/testing_device_token_fetcher.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/test/testing_device_token_fetcher.h" - -#include "chrome/common/notification_service.h" -#include "chrome/common/notification_source.h" -#include "chrome/common/notification_type.h" -#include "chrome/browser/policy/device_token_fetcher.h" -#include "chrome/browser/profiles/profile.h" - -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/user_manager.h" -#else -#include "chrome/browser/sync/signin_manager.h" -#endif - -namespace policy { - -const char* kTestManagedDomainUsername = "___@example.com"; - -void TestingDeviceTokenFetcher::SimulateLogin(const std::string& username) { - username_ = username; -#if defined(OS_CHROMEOS) - chromeos::UserManager::User user; - user.set_email(username_); - NotificationService::current()->Notify( - NotificationType::LOGIN_USER_CHANGED, - Source<chromeos::UserManager>(NULL), - Details<const chromeos::UserManager::User>(&user)); -#else - GoogleServiceSigninSuccessDetails details(username_, ""); - NotificationService::current()->Notify( - NotificationType::GOOGLE_SIGNIN_SUCCESSFUL, - Source<Profile>(profile_), - Details<const GoogleServiceSigninSuccessDetails>(&details)); -#endif -} - -std::string TestingDeviceTokenFetcher::GetCurrentUser() { - return username_; -} - -} // namespace policy diff --git a/chrome/test/testing_device_token_fetcher.h b/chrome/test/testing_device_token_fetcher.h deleted file mode 100644 index ab021f9..0000000 --- a/chrome/test/testing_device_token_fetcher.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_TEST_TESTING_DEVICE_TOKEN_FETCHER_H_ -#define CHROME_TEST_TESTING_DEVICE_TOKEN_FETCHER_H_ -#pragma once - -#include <string> - -#include "chrome/browser/policy/device_token_fetcher.h" - -class DeviceTokenService; -class Profile; - -namespace policy { - -extern const char* kTestManagedDomainUsername; - -// Replacement for DeviceTokenFetcher in tests. The only difference in internal -// logic is that the name of the currently logged in user is not fetched from -// external objects, but stored internally. -class TestingDeviceTokenFetcher - : public DeviceTokenFetcher { - public: - TestingDeviceTokenFetcher( - DeviceManagementBackend* backend, - Profile* profile, - const FilePath& token_path) - : DeviceTokenFetcher(backend, profile, token_path) {} - - void SimulateLogin(const std::string& username); - - protected: - virtual std::string GetCurrentUser(); - - private: - // This username will be reported as currently logged in. - std::string username_; - - DISALLOW_COPY_AND_ASSIGN(TestingDeviceTokenFetcher); -}; - -} // namespace policy - -#endif // CHROME_TEST_TESTING_DEVICE_TOKEN_FETCHER_H_ diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc index d523541..dace243 100644 --- a/chrome/test/testing_profile.cc +++ b/chrome/test/testing_profile.cc @@ -766,7 +766,7 @@ PromoCounter* TestingProfile::GetInstantPromoCounter() { return NULL; } -policy::ProfilePolicyContext* TestingProfile::GetPolicyContext() { +policy::ProfilePolicyConnector* TestingProfile::GetPolicyConnector() { return NULL; } diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index 822acb9..ad437d8 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -280,7 +280,7 @@ class TestingProfile : public Profile { virtual ChromeBlobStorageContext* GetBlobStorageContext(); virtual ExtensionInfoMap* GetExtensionInfoMap(); virtual PromoCounter* GetInstantPromoCounter(); - virtual policy::ProfilePolicyContext* GetPolicyContext(); + virtual policy::ProfilePolicyConnector* GetPolicyConnector(); virtual ChromeURLDataManager* GetChromeURLDataManager(); virtual prerender::PrerenderManager* GetPrerenderManager(); virtual PrefService* GetOffTheRecordPrefs(); |