diff options
author | jkummerow@chromium.org <jkummerow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-11 10:59:08 +0000 |
---|---|---|
committer | jkummerow@chromium.org <jkummerow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-11 10:59:08 +0000 |
commit | 6ced4e79b6b816022957ca3dbad7712b49aa2f36 (patch) | |
tree | 1ab8d3426c1f5f902745b37d20382a4befdd97f0 | |
parent | 087b8c8ecf6630ab31d30913148e0e613a0ab881 (diff) | |
download | chromium_src-6ced4e79b6b816022957ca3dbad7712b49aa2f36.zip chromium_src-6ced4e79b6b816022957ca3dbad7712b49aa2f36.tar.gz chromium_src-6ced4e79b6b816022957ca3dbad7712b49aa2f36.tar.bz2 |
Provide backend methods for device enrollment UI
BUG=chromium-os:13277
TEST=Existing unit tests
Review URL: http://codereview.chromium.org/6794022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81088 0039d316-1c4b-4281-b951-d872f2087c98
31 files changed, 739 insertions, 371 deletions
diff --git a/chrome/browser/chromeos/login/signed_settings.cc b/chrome/browser/chromeos/login/signed_settings.cc index 8eec528..6e90a93 100644 --- a/chrome/browser/chromeos/login/signed_settings.cc +++ b/chrome/browser/chromeos/login/signed_settings.cc @@ -30,7 +30,7 @@ SignedSettings::~SignedSettings() {} SignedSettings::ReturnCode SignedSettings::MapKeyOpCode( OwnerManager::KeyOpCode return_code) { return (return_code == OwnerManager::KEY_UNAVAILABLE ? - KEY_UNAVAILABLE : OPERATION_FAILED); + KEY_UNAVAILABLE : BAD_SIGNATURE); } void SignedSettings::OnBoolComplete(void* delegate, bool success) { @@ -543,10 +543,14 @@ void RetrievePolicyOp::ProcessPolicy(const char* out, const unsigned int len) { d_->OnSettingsOpCompleted(NOT_FOUND, policy_); return; } - if (!policy_.has_policy_data() || !policy_.has_policy_data_signature()) { + if (!policy_.has_policy_data()) { d_->OnSettingsOpCompleted(OPERATION_FAILED, em::PolicyFetchResponse()); return; } + if (!policy_.has_policy_data_signature()) { + d_->OnSettingsOpCompleted(BAD_SIGNATURE, em::PolicyFetchResponse()); + return; + } std::vector<uint8> sig; const char* sig_ptr = policy_.policy_data_signature().c_str(); sig.assign(sig_ptr, sig_ptr + policy_.policy_data_signature().length()); diff --git a/chrome/browser/chromeos/login/signed_settings.h b/chrome/browser/chromeos/login/signed_settings.h index 01092e5..1a374d2 100644 --- a/chrome/browser/chromeos/login/signed_settings.h +++ b/chrome/browser/chromeos/login/signed_settings.h @@ -7,6 +7,7 @@ #pragma once #include <string> +#include <vector> #include "base/memory/ref_counted.h" #include "chrome/browser/chromeos/login/owner_manager.h" @@ -42,9 +43,10 @@ class SignedSettings : public base::RefCountedThreadSafe<SignedSettings>, public: enum ReturnCode { SUCCESS, - NOT_FOUND, // Email address or property name not found. - KEY_UNAVAILABLE, // Owner key not yet configured. - OPERATION_FAILED // Signature op or IPC to signed settings daemon failed. + NOT_FOUND, // Email address or property name not found. + KEY_UNAVAILABLE, // Owner key not yet configured. + OPERATION_FAILED, // IPC to signed settings daemon failed. + BAD_SIGNATURE // Signature verification failed. }; template <class T> diff --git a/chrome/browser/chromeos/login/signed_settings_unittest.cc b/chrome/browser/chromeos/login/signed_settings_unittest.cc index e477388..6570cac 100644 --- a/chrome/browser/chromeos/login/signed_settings_unittest.cc +++ b/chrome/browser/chromeos/login/signed_settings_unittest.cc @@ -490,8 +490,7 @@ TEST_F(SignedSettingsTest, StorePolicyFailed) { TEST_F(SignedSettingsTest, StorePolicyNoPolicyData) { NormalDelegate<bool> d(false); - d.expect_failure( - SignedSettings::MapKeyOpCode(OwnerManager::OPERATION_FAILED)); + d.expect_failure(SignedSettings::OPERATION_FAILED); std::string serialized; em::PolicyFetchResponse fake_policy = BuildProto(std::string(), @@ -573,7 +572,7 @@ TEST_F(SignedSettingsTest, RetrieveUnsignedPolicy) { std::string(), &serialized); ProtoDelegate d(policy); - d.expect_failure(SignedSettings::OPERATION_FAILED); + d.expect_failure(SignedSettings::BAD_SIGNATURE); scoped_refptr<SignedSettings> s(SignedSettings::CreateRetrievePolicyOp(&d)); MockLoginLibrary* lib = MockLoginLib(); @@ -594,7 +593,7 @@ TEST_F(SignedSettingsTest, RetrieveMalsignedPolicy) { fake_value_, &signed_serialized); ProtoDelegate d(signed_policy); - d.expect_failure(SignedSettings::OPERATION_FAILED); + d.expect_failure(SignedSettings::BAD_SIGNATURE); scoped_refptr<SignedSettings> s(SignedSettings::CreateRetrievePolicyOp(&d)); MockLoginLibrary* lib = MockLoginLib(); diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc index b11d16e..df75c9b 100644 --- a/chrome/browser/policy/browser_policy_connector.cc +++ b/chrome/browser/policy/browser_policy_connector.cc @@ -8,7 +8,6 @@ #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" @@ -45,9 +44,9 @@ BrowserPolicyConnector::BrowserPolicyConnector() { CommandLine* command_line = CommandLine::ForCurrentProcess(); if (command_line->HasSwitch(switches::kEnableDevicePolicy)) { identity_strategy_.reset(new DevicePolicyIdentityStrategy()); - cloud_policy_subsystem_.reset( - new CloudPolicySubsystem(identity_strategy_.get(), - new DevicePolicyCache())); + cloud_policy_subsystem_.reset(new CloudPolicySubsystem( + identity_strategy_.get(), + new DevicePolicyCache(identity_strategy_.get()))); } #endif } @@ -62,7 +61,9 @@ BrowserPolicyConnector::~BrowserPolicyConnector() { if (cloud_policy_subsystem_.get()) cloud_policy_subsystem_->Shutdown(); cloud_policy_subsystem_.reset(); +#if defined(OS_CHROMEOS) identity_strategy_.reset(); +#endif } ConfigurationPolicyProvider* @@ -137,6 +138,29 @@ void BrowserPolicyConnector::RegisterPrefs(PrefService* local_state) { kDefaultPolicyRefreshRateInMilliseconds); } +void BrowserPolicyConnector::SetCredentials(const std::string& owner_email, + const std::string& gaia_token, + const std::string& machine_id) { +#if defined(OS_CHROMEOS) + if (identity_strategy_.get()) + identity_strategy_->SetAuthCredentials(owner_email, gaia_token, machine_id); +#endif +} + +bool BrowserPolicyConnector::IsEnterpriseManaged() { +#if defined(OS_CHROMEOS) + return (identity_strategy_.get() && + !identity_strategy_->GetDeviceToken().empty()); +#else + return false; +#endif +} + +void BrowserPolicyConnector::StopAutoRetry() { + if (cloud_policy_subsystem_.get()) + cloud_policy_subsystem_->StopAutoRetry(); +} + void BrowserPolicyConnector::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { diff --git a/chrome/browser/policy/browser_policy_connector.h b/chrome/browser/policy/browser_policy_connector.h index 2271f213..93995c8 100644 --- a/chrome/browser/policy/browser_policy_connector.h +++ b/chrome/browser/policy/browser_policy_connector.h @@ -6,6 +6,8 @@ #define CHROME_BROWSER_POLICY_BROWSER_POLICY_CONNECTOR_H_ #pragma once +#include <string> + #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "content/common/notification_observer.h" @@ -21,9 +23,9 @@ class URLRequestContextGetter; namespace policy { -class CloudPolicyIdentityStrategy; class CloudPolicySubsystem; class ConfigurationPolicyProvider; +class DevicePolicyIdentityStrategy; // Manages the lifecycle of browser-global policy infrastructure, such as the // platform policy providers. @@ -40,8 +42,30 @@ class BrowserPolicyConnector : public NotificationObserver { ConfigurationPolicyProvider* GetRecommendedPlatformProvider() const; ConfigurationPolicyProvider* GetRecommendedCloudProvider() const; + // Returns a weak pointer to the CloudPolicySubsystem managed by this + // policy connector, or NULL if no such subsystem exists (i.e. when running + // outside ChromeOS). + CloudPolicySubsystem* cloud_policy_subsystem() { + return cloud_policy_subsystem_.get(); + } + static void RegisterPrefs(PrefService* user_prefs); + // Used to set the credentials stored in the identity strategy associated + // with this policy connector. + void SetCredentials(const std::string& owner_email, + const std::string& gaia_token, + const std::string& machine_id); + + // Returns true if this device is managed by an enterprise (as opposed to + // a local owner). + bool IsEnterpriseManaged(); + + // Exposes the StopAutoRetry() method of the CloudPolicySubsystem managed + // by this connector, which can be used to disable automatic + // retrying behavior. + void StopAutoRetry(); + // NotificationObserver implementation: virtual void Observe(NotificationType type, const NotificationSource& source, @@ -67,7 +91,9 @@ class BrowserPolicyConnector : public NotificationObserver { scoped_ptr<ConfigurationPolicyProvider> managed_platform_provider_; scoped_ptr<ConfigurationPolicyProvider> recommended_platform_provider_; - scoped_ptr<CloudPolicyIdentityStrategy> identity_strategy_; +#if defined(OS_CHROMEOS) + scoped_ptr<DevicePolicyIdentityStrategy> identity_strategy_; +#endif scoped_ptr<CloudPolicySubsystem> cloud_policy_subsystem_; NotificationRegistrar registrar_; diff --git a/chrome/browser/policy/cloud_policy_cache_base.cc b/chrome/browser/policy/cloud_policy_cache_base.cc index 8af7533..3f1f48c 100644 --- a/chrome/browser/policy/cloud_policy_cache_base.cc +++ b/chrome/browser/policy/cloud_policy_cache_base.cc @@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/values.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" +#include "chrome/browser/policy/policy_notifier.h" namespace policy { @@ -54,7 +55,8 @@ class CloudPolicyCacheBase::CloudPolicyProvider }; CloudPolicyCacheBase::CloudPolicyCacheBase() - : initialization_complete_(false), + : notifier_(NULL), + initialization_complete_(false), is_unmanaged_(false) { managed_policy_provider_.reset( new CloudPolicyProvider( @@ -109,6 +111,8 @@ bool CloudPolicyCacheBase::SetPolicyInternal( FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, observer_list_, OnUpdatePolicy()); } + InformNotifier(CloudPolicySubsystem::SUCCESS, + CloudPolicySubsystem::NO_DETAILS); return true; } @@ -152,4 +156,13 @@ bool CloudPolicyCacheBase::DecodePolicyResponse( return DecodePolicyData(policy_data, mandatory, recommended); } +void CloudPolicyCacheBase::InformNotifier( + CloudPolicySubsystem::PolicySubsystemState state, + CloudPolicySubsystem::ErrorDetails error_details) { + // TODO(jkummerow): To obsolete this NULL-check, make all uses of + // UserPolicyCache explicitly set a notifier using |set_policy_notifier()|. + if (notifier_) + notifier_->Inform(state, error_details, PolicyNotifier::POLICY_CACHE); +} + } // namespace policy diff --git a/chrome/browser/policy/cloud_policy_cache_base.h b/chrome/browser/policy/cloud_policy_cache_base.h index 44cfd87..f97d6cf 100644 --- a/chrome/browser/policy/cloud_policy_cache_base.h +++ b/chrome/browser/policy/cloud_policy_cache_base.h @@ -11,6 +11,7 @@ #include "base/observer_list.h" #include "base/threading/non_thread_safe.h" #include "base/time.h" +#include "chrome/browser/policy/cloud_policy_subsystem.h" #include "chrome/browser/policy/configuration_policy_provider.h" #include "chrome/browser/policy/policy_map.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" @@ -18,6 +19,7 @@ namespace policy { class PolicyMap; +class PolicyNotifier; namespace em = enterprise_management; @@ -37,6 +39,10 @@ class CloudPolicyCacheBase : public base::NonThreadSafe { CloudPolicyCacheBase(); virtual ~CloudPolicyCacheBase(); + void set_policy_notifier(PolicyNotifier* notifier) { + notifier_ = notifier; + } + // Loads persisted policy information. virtual void Load() = 0; @@ -82,6 +88,9 @@ class CloudPolicyCacheBase : public base::NonThreadSafe { PolicyMap* recommended, base::Time* timestamp); + void InformNotifier(CloudPolicySubsystem::PolicySubsystemState state, + CloudPolicySubsystem::ErrorDetails error_details); + // See comment for |initialization_complete_|. bool initialization_complete() { return initialization_complete_; @@ -105,6 +114,8 @@ class CloudPolicyCacheBase : public base::NonThreadSafe { scoped_ptr<ConfigurationPolicyProvider> managed_policy_provider_; scoped_ptr<ConfigurationPolicyProvider> recommended_policy_provider_; + PolicyNotifier* notifier_; + // The time at which the policy was last refreshed. Is updated both upon // successful and unsuccessful refresh attempts. base::Time last_policy_refresh_time_; diff --git a/chrome/browser/policy/cloud_policy_controller.cc b/chrome/browser/policy/cloud_policy_controller.cc index 9337b02..60171b1 100644 --- a/chrome/browser/policy/cloud_policy_controller.cc +++ b/chrome/browser/policy/cloud_policy_controller.cc @@ -13,6 +13,7 @@ #include "chrome/browser/policy/cloud_policy_cache_base.h" #include "chrome/browser/policy/cloud_policy_subsystem.h" #include "chrome/browser/policy/device_management_backend.h" +#include "chrome/browser/policy/device_management_service.h" #include "chrome/browser/policy/proto/device_management_constants.h" // Domain names that are known not to be managed. @@ -60,15 +61,17 @@ static const int kPolicyRefreshRateInMilliseconds = 3 * 60 * 60 * 1000; // 3 hours. CloudPolicyController::CloudPolicyController( + DeviceManagementService* service, CloudPolicyCacheBase* cache, - DeviceManagementBackend* backend, DeviceTokenFetcher* token_fetcher, - CloudPolicyIdentityStrategy* identity_strategy) + CloudPolicyIdentityStrategy* identity_strategy, + PolicyNotifier* notifier) : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { - Initialize(cache, - backend, + Initialize(service, + cache, token_fetcher, identity_strategy, + notifier, kPolicyRefreshRateInMilliseconds, kPolicyRefreshDeviationFactorPercent, kPolicyRefreshDeviationMaxInMilliseconds, @@ -89,17 +92,13 @@ void CloudPolicyController::SetRefreshRate(int64 refresh_rate_milliseconds) { SetState(STATE_POLICY_VALID); } +void CloudPolicyController::StopAutoRetry() { + CancelDelayedWork(); + backend_.reset(); +} + void CloudPolicyController::HandlePolicyResponse( const em::DevicePolicyResponse& response) { - // In case state has changed by the user while request was in progress ignore - // the answer. - if (state_ == STATE_TOKEN_UNAVAILABLE || - state_ == STATE_TOKEN_UNMANAGED || - state_ == STATE_TOKEN_ERROR) { - LOG(WARNING) << "Unexpected reply from policy server received. Ignoring."; - return; - } - if (response.response_size() > 0) { if (response.response_size() > 1) { LOG(WARNING) << "More than one policy in the response of the device " @@ -116,15 +115,6 @@ void CloudPolicyController::HandlePolicyResponse( } void CloudPolicyController::OnError(DeviceManagementBackend::ErrorCode code) { - // In case state has changed by the user while request was in progress ignore - // the answer. - if (state_ == STATE_TOKEN_UNAVAILABLE || - state_ == STATE_TOKEN_UNMANAGED || - state_ == STATE_TOKEN_ERROR) { - LOG(WARNING) << "Unexpected reply from policy server received. Ignoring."; - return; - } - switch (code) { case DeviceManagementBackend::kErrorServiceDeviceNotFound: case DeviceManagementBackend::kErrorServiceManagementTokenInvalid: { @@ -177,19 +167,21 @@ void CloudPolicyController::OnCredentialsChanged() { } CloudPolicyController::CloudPolicyController( + DeviceManagementService* service, CloudPolicyCacheBase* cache, - DeviceManagementBackend* backend, DeviceTokenFetcher* token_fetcher, CloudPolicyIdentityStrategy* identity_strategy, + PolicyNotifier* notifier, 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, + Initialize(service, + cache, token_fetcher, identity_strategy, + notifier, policy_refresh_rate_ms, policy_refresh_deviation_factor_percent, policy_refresh_deviation_max_ms, @@ -197,20 +189,22 @@ CloudPolicyController::CloudPolicyController( } void CloudPolicyController::Initialize( + DeviceManagementService* service, CloudPolicyCacheBase* cache, - DeviceManagementBackend* backend, DeviceTokenFetcher* token_fetcher, CloudPolicyIdentityStrategy* identity_strategy, + PolicyNotifier* notifier, 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); + service_ = service; cache_ = cache; - backend_.reset(backend); token_fetcher_ = token_fetcher; identity_strategy_ = identity_strategy; + notifier_ = notifier; state_ = STATE_TOKEN_UNAVAILABLE; delayed_work_task_ = NULL; policy_refresh_rate_ms_ = policy_refresh_rate_ms; @@ -242,6 +236,7 @@ void CloudPolicyController::FetchToken() { } void CloudPolicyController::SendPolicyRequest() { + backend_.reset(service_->CreateBackend()); DCHECK(!identity_strategy_->GetDeviceToken().empty()); em::DevicePolicyRequest policy_request; em::PolicyFetchRequest* fetch_request = policy_request.add_request(); @@ -262,7 +257,10 @@ void CloudPolicyController::SendPolicyRequest() { void CloudPolicyController::DoDelayedWork() { DCHECK(delayed_work_task_); delayed_work_task_ = NULL; + DoWork(); +} +void CloudPolicyController::DoWork() { switch (state_) { case STATE_TOKEN_UNAVAILABLE: case STATE_TOKEN_ERROR: @@ -291,6 +289,7 @@ void CloudPolicyController::CancelDelayedWork() { void CloudPolicyController::SetState( CloudPolicyController::ControllerState new_state) { state_ = new_state; + backend_.reset(); // Discard any pending requests. base::Time now(base::Time::NowFromSystemTime()); base::Time refresh_at; @@ -299,8 +298,12 @@ void CloudPolicyController::SetState( last_refresh = now; // Determine when to take the next step. + bool inform_notifier_done = false; switch (state_) { case STATE_TOKEN_UNMANAGED: + notifier_->Inform(CloudPolicySubsystem::UNMANAGED, + CloudPolicySubsystem::NO_DETAILS, + PolicyNotifier::POLICY_CONTROLLER); break; case STATE_TOKEN_UNAVAILABLE: // The controller is not yet initialized and needs to immediately fetch @@ -309,6 +312,8 @@ void CloudPolicyController::SetState( // Immediately try to fetch the token on initialization or policy after a // token update. Subsequent retries will respect the back-off strategy. refresh_at = now; + // |notifier_| isn't informed about anything at this point, we wait for + // the result of the next action first. break; case STATE_POLICY_VALID: // Delay is only reset if the policy fetch operation was successful. This @@ -317,9 +322,21 @@ void CloudPolicyController::SetState( effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms_; refresh_at = last_refresh + base::TimeDelta::FromMilliseconds(GetRefreshDelay()); + notifier_->Inform(CloudPolicySubsystem::SUCCESS, + CloudPolicySubsystem::NO_DETAILS, + PolicyNotifier::POLICY_CONTROLLER); break; case STATE_TOKEN_ERROR: + notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR, + CloudPolicySubsystem::BAD_DMTOKEN, + PolicyNotifier::POLICY_CONTROLLER); + inform_notifier_done = true; case STATE_POLICY_ERROR: + if (!inform_notifier_done) { + notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR, + CloudPolicySubsystem::POLICY_NETWORK_ERROR, + PolicyNotifier::POLICY_CONTROLLER); + } refresh_at = now + base::TimeDelta::FromMilliseconds( effective_policy_refresh_error_delay_ms_); effective_policy_refresh_error_delay_ms_ = @@ -330,6 +347,9 @@ void CloudPolicyController::SetState( effective_policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_; refresh_at = now + base::TimeDelta::FromMilliseconds( effective_policy_refresh_error_delay_ms_); + notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR, + CloudPolicySubsystem::POLICY_NETWORK_ERROR, + PolicyNotifier::POLICY_CONTROLLER); break; } diff --git a/chrome/browser/policy/cloud_policy_controller.h b/chrome/browser/policy/cloud_policy_controller.h index 1bc316b..61ff3bb 100644 --- a/chrome/browser/policy/cloud_policy_controller.h +++ b/chrome/browser/policy/cloud_policy_controller.h @@ -35,15 +35,20 @@ class CloudPolicyController public CloudPolicyIdentityStrategy::Observer { public: // Takes ownership of |backend|; the other parameters are weak pointers. - CloudPolicyController(CloudPolicyCacheBase* cache, - DeviceManagementBackend* backend, + CloudPolicyController(DeviceManagementService* service, + CloudPolicyCacheBase* cache, DeviceTokenFetcher* token_fetcher, - CloudPolicyIdentityStrategy* identity_strategy); + CloudPolicyIdentityStrategy* identity_strategy, + PolicyNotifier* notifier); virtual ~CloudPolicyController(); // Sets the refresh rate at which to re-fetch policy information. void SetRefreshRate(int64 refresh_rate_milliseconds); + // Stops all auto-retrying error handling behavior inside the policy + // subsystem. + void StopAutoRetry(); + // DevicePolicyResponseDelegate implementation: virtual void HandlePolicyResponse( const em::DevicePolicyResponse& response); @@ -78,20 +83,22 @@ class CloudPolicyController friend class CloudPolicyControllerTest; // More configurable constructor for use by test cases. - CloudPolicyController(CloudPolicyCacheBase* cache, - DeviceManagementBackend* backend, + CloudPolicyController(DeviceManagementService* service, + CloudPolicyCacheBase* cache, DeviceTokenFetcher* token_fetcher, CloudPolicyIdentityStrategy* identity_strategy, + PolicyNotifier* notifier, 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(CloudPolicyCacheBase* cache, - DeviceManagementBackend* backend, + void Initialize(DeviceManagementService* service, + CloudPolicyCacheBase* cache, DeviceTokenFetcher* token_fetcher, CloudPolicyIdentityStrategy* identity_strategy, + PolicyNotifier* notifier, int64 policy_refresh_rate_ms, int policy_refresh_deviation_factor_percent, int64 policy_refresh_deviation_max_ms, @@ -104,10 +111,13 @@ class CloudPolicyController // 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. + // Called back from the delayed work task. Calls |DoWork()|. void DoDelayedWork(); + // Performs whatever action is required in the current state, + // e.g. refreshing policy. + void DoWork(); + // Cancels the delayed work task. void CancelDelayedWork(); @@ -117,12 +127,14 @@ class CloudPolicyController // Computes the policy refresh delay to use. int64 GetRefreshDelay(); + DeviceManagementService* service_; CloudPolicyCacheBase* cache_; - scoped_ptr<DeviceManagementBackend> backend_; CloudPolicyIdentityStrategy* identity_strategy_; DeviceTokenFetcher* token_fetcher_; + scoped_ptr<DeviceManagementBackend> backend_; ControllerState state_; bool initial_fetch_done_; + PolicyNotifier* notifier_; int64 policy_refresh_rate_ms_; int policy_refresh_deviation_factor_percent_; diff --git a/chrome/browser/policy/cloud_policy_controller_unittest.cc b/chrome/browser/policy/cloud_policy_controller_unittest.cc index 6419521..e3569b9 100644 --- a/chrome/browser/policy/cloud_policy_controller_unittest.cc +++ b/chrome/browser/policy/cloud_policy_controller_unittest.cc @@ -6,9 +6,12 @@ #include "base/memory/scoped_temp_dir.h" #include "base/message_loop.h" +#include "chrome/browser/policy/device_management_service.h" #include "chrome/browser/policy/device_token_fetcher.h" #include "chrome/browser/policy/mock_configuration_policy_store.h" #include "chrome/browser/policy/mock_device_management_backend.h" +#include "chrome/browser/policy/mock_device_management_service.h" +#include "chrome/browser/policy/policy_notifier.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "chrome/browser/policy/user_policy_cache.h" #include "content/browser/browser_thread.h" @@ -55,7 +58,7 @@ ACTION_P2(MockCloudPolicyIdentityStrategyGetCredentials, username, auth_token) { class MockDeviceTokenFetcher : public DeviceTokenFetcher { public: explicit MockDeviceTokenFetcher(CloudPolicyCacheBase* cache) - : DeviceTokenFetcher(NULL, cache) {} + : DeviceTokenFetcher(NULL, cache, NULL) {} virtual ~MockDeviceTokenFetcher() {} MOCK_METHOD0(GetDeviceToken, const std::string&()); @@ -81,6 +84,7 @@ class CloudPolicyControllerTest : public testing::Test { cache_.reset(new UserPolicyCache( temp_user_data_dir_.path().AppendASCII("CloudPolicyControllerTest"))); token_fetcher_.reset(new MockDeviceTokenFetcher(cache_.get())); + service_.set_backend(&backend_); } virtual void TearDown() { @@ -88,18 +92,19 @@ class CloudPolicyControllerTest : public testing::Test { } // Takes ownership of |backend|. - void CreateNewController(DeviceManagementBackend* backend) { + void CreateNewController() { controller_.reset(new CloudPolicyController( - cache_.get(), backend, token_fetcher_.get(), &identity_strategy_)); + &service_, cache_.get(), token_fetcher_.get(), &identity_strategy_, + ¬ifier_)); } - void CreateNewController(DeviceManagementBackend* backend, - int64 policy_refresh_rate_ms, + void CreateNewController(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_, + &service_, cache_.get(), token_fetcher_.get(), &identity_strategy_, + ¬ifier_, policy_refresh_rate_ms, policy_refresh_deviation_factor_percent, policy_refresh_deviation_max_ms, @@ -144,6 +149,9 @@ class CloudPolicyControllerTest : public testing::Test { scoped_ptr<CloudPolicyController> controller_; scoped_ptr<MockDeviceTokenFetcher> token_fetcher_; MockCloudPolicyIdentityStrategy identity_strategy_; + MockDeviceManagementBackend backend_; + MockDeviceManagementService service_; + PolicyNotifier notifier_; ScopedTempDir temp_user_data_dir_; MessageLoop loop_; @@ -160,10 +168,9 @@ TEST_F(CloudPolicyControllerTest, StartupWithDeviceToken) { SetupIdentityStrategy("fake_device_token", "device_id", "machine_id", "google/chromeos/user", em::DeviceRegisterRequest::USER, "", ""); - MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); - EXPECT_CALL(*backend, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - CreateNewController(backend); + CreateNewController(); loop_.RunAllPending(); ExpectHasSpdyPolicy(); } @@ -175,7 +182,7 @@ TEST_F(CloudPolicyControllerTest, StartupWithoutDeviceToken) { em::DeviceRegisterRequest::USER, "a@b.com", "auth_token"); EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _, _, _)).Times(1); - CreateNewController(NULL); + CreateNewController(); loop_.RunAllPending(); } @@ -186,7 +193,7 @@ TEST_F(CloudPolicyControllerTest, StartupUnmanagedUser) { em::DeviceRegisterRequest::USER, "DannoHelper@gmail.com", "auth_token"); EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _, _, _)).Times(0); - CreateNewController(NULL); + CreateNewController(); loop_.RunAllPending(); } @@ -196,12 +203,11 @@ TEST_F(CloudPolicyControllerTest, RefreshAfterSuccessfulPolicy) { SetupIdentityStrategy("device_token", "device_id", "machine_id", "google/chromeos/user", em::DeviceRegisterRequest::USER, "DannoHelperDelegate@b.com", "auth_token"); - MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); - EXPECT_CALL(*backend, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedSpdyCloudPolicy()).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorRequestFailed)); - CreateNewController(backend, 0, 0, 0, 1000 * 1000); + CreateNewController(0, 0, 0, 1000 * 1000); loop_.RunAllPending(); ExpectHasSpdyPolicy(); } @@ -211,12 +217,11 @@ TEST_F(CloudPolicyControllerTest, RefreshAfterError) { SetupIdentityStrategy("device_token", "device_id", "machine_id", "google/chromeos/user", em::DeviceRegisterRequest::USER, "DannoHelperDelegateImpl@b.com", "auth_token"); - MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); - EXPECT_CALL(*backend, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorRequestFailed)).WillOnce( MockDeviceManagementBackendSucceedSpdyCloudPolicy()); - CreateNewController(backend, 1000 * 1000, 0, 0, 0); + CreateNewController(1000 * 1000, 0, 0, 0); loop_.RunAllPending(); ExpectHasSpdyPolicy(); } @@ -227,12 +232,11 @@ TEST_F(CloudPolicyControllerTest, InvalidToken) { SetupIdentityStrategy("device_token", "device_id", "machine_id", "google/chromeos/user", em::DeviceRegisterRequest::USER, "standup@ten.am", "auth"); - MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); - EXPECT_CALL(*backend, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorServiceManagementTokenInvalid)); EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _, _, _)).Times(1); - CreateNewController(backend, 1000 * 1000, 0, 0, 0); + CreateNewController(1000 * 1000, 0, 0, 0); loop_.RunAllPending(); } @@ -242,12 +246,11 @@ TEST_F(CloudPolicyControllerTest, DeviceNotFound) { SetupIdentityStrategy("device_token", "device_id", "machine_id", "google/chromeos/user", em::DeviceRegisterRequest::USER, "me@you.com", "auth"); - MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); - EXPECT_CALL(*backend, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorServiceDeviceNotFound)); EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _, _, _)).Times(1); - CreateNewController(backend, 1000 * 1000, 0, 0, 0); + CreateNewController(1000 * 1000, 0, 0, 0); loop_.RunAllPending(); } @@ -258,12 +261,11 @@ TEST_F(CloudPolicyControllerTest, NoLongerManaged) { SetupIdentityStrategy("device_token", "device_id", "machine_id", "google/chromeos/user", em::DeviceRegisterRequest::USER, "who@what.com", "auth"); - MockDeviceManagementBackend* backend = new MockDeviceManagementBackend(); - EXPECT_CALL(*backend, ProcessPolicyRequest(_, _, _, _)).WillOnce( + EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendFailPolicy( DeviceManagementBackend::kErrorServiceManagementNotSupported)); EXPECT_CALL(*token_fetcher_.get(), SetUnmanagedState()).Times(1); - CreateNewController(backend, 0, 0, 0, 1000 * 1000); + CreateNewController(0, 0, 0, 1000 * 1000); loop_.RunAllPending(); } diff --git a/chrome/browser/policy/cloud_policy_subsystem.cc b/chrome/browser/policy/cloud_policy_subsystem.cc index 59bc04f..031dab2 100644 --- a/chrome/browser/policy/cloud_policy_subsystem.cc +++ b/chrome/browser/policy/cloud_policy_subsystem.cc @@ -14,6 +14,7 @@ #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/browser/policy/policy_notifier.h" #include "chrome/common/chrome_switches.h" #include "content/common/notification_details.h" #include "content/common/notification_source.h" @@ -29,26 +30,43 @@ const int64 kPolicyRefreshRateMaxMs = 24 * 60 * 60 * 1000; // 1 day namespace policy { +CloudPolicySubsystem::ObserverRegistrar::ObserverRegistrar( + CloudPolicySubsystem* cloud_policy_subsystem, + CloudPolicySubsystem::Observer* observer) + : observer_(observer) { + policy_notifier_ = cloud_policy_subsystem->notifier(); + policy_notifier_->AddObserver(observer); +} + +CloudPolicySubsystem::ObserverRegistrar::~ObserverRegistrar() { + if (policy_notifier_) + policy_notifier_->RemoveObserver(observer_); +} + CloudPolicySubsystem::CloudPolicySubsystem( CloudPolicyIdentityStrategy* identity_strategy, CloudPolicyCacheBase* policy_cache) : prefs_(NULL) { + notifier_.reset(new PolicyNotifier()); 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(policy_cache); + cloud_policy_cache_->set_policy_notifier(notifier_.get()); cloud_policy_cache_->Load(); device_token_fetcher_.reset( new DeviceTokenFetcher(device_management_service_.get(), - cloud_policy_cache_.get())); + cloud_policy_cache_.get(), + notifier_.get())); cloud_policy_controller_.reset( - new CloudPolicyController(cloud_policy_cache_.get(), - device_management_service_->CreateBackend(), + new CloudPolicyController(device_management_service_.get(), + cloud_policy_cache_.get(), device_token_fetcher_.get(), - identity_strategy)); + identity_strategy, + notifier_.get())); } } @@ -83,6 +101,19 @@ void CloudPolicySubsystem::Shutdown() { prefs_ = NULL; } +CloudPolicySubsystem::PolicySubsystemState CloudPolicySubsystem::state() { + return notifier_->state(); +} + +CloudPolicySubsystem::ErrorDetails CloudPolicySubsystem::error_details() { + return notifier_->error_details(); +} + +void CloudPolicySubsystem::StopAutoRetry() { + cloud_policy_controller_->StopAutoRetry(); + device_token_fetcher_->StopAutoRetry(); +} + ConfigurationPolicyProvider* CloudPolicySubsystem::GetManagedPolicyProvider() { if (cloud_policy_cache_.get()) return cloud_policy_cache_->GetManagedPolicyProvider(); diff --git a/chrome/browser/policy/cloud_policy_subsystem.h b/chrome/browser/policy/cloud_policy_subsystem.h index 3b49339..ab1744c 100644 --- a/chrome/browser/policy/cloud_policy_subsystem.h +++ b/chrome/browser/policy/cloud_policy_subsystem.h @@ -24,12 +24,50 @@ class CloudPolicyIdentityStrategy; class ConfigurationPolicyProvider; class DeviceManagementService; class DeviceTokenFetcher; +class PolicyNotifier; // 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: + enum PolicySubsystemState { + UNENROLLED, // No enrollment attempt has been performed yet. + BAD_GAIA_TOKEN, // The server rejected the GAIA auth token. + UNMANAGED, // This device is unmanaged. + NETWORK_ERROR, // A network error occurred, retrying makes sense. + LOCAL_ERROR, // Retrying is futile. + SUCCESS // Policy has been fetched successfully and is in effect. + }; + + enum ErrorDetails { + NO_DETAILS, // No error, so no error details either. + DMTOKEN_NETWORK_ERROR, // DeviceTokenFetcher encountered a network error. + POLICY_NETWORK_ERROR, // CloudPolicyController encountered a network error. + BAD_DMTOKEN, // The server rejected the DMToken. + POLICY_LOCAL_ERROR, // The policy cache encountered a local error. + SIGNATURE_MISMATCH, // The policy cache detected a signature mismatch. + }; + + class Observer { + public: + virtual ~Observer() {} + virtual void OnPolicyStateChanged(PolicySubsystemState state, + ErrorDetails error_details) = 0; + }; + + class ObserverRegistrar { + public: + ObserverRegistrar(CloudPolicySubsystem* cloud_policy_subsystem, + CloudPolicySubsystem::Observer* observer); + ~ObserverRegistrar(); + + private: + PolicyNotifier* policy_notifier_; + CloudPolicySubsystem::Observer* observer_; + DISALLOW_COPY_AND_ASSIGN(ObserverRegistrar); + }; + CloudPolicySubsystem(CloudPolicyIdentityStrategy* identity_strategy, CloudPolicyCacheBase* policy_cache); virtual ~CloudPolicySubsystem(); @@ -43,6 +81,14 @@ class CloudPolicySubsystem : public NotificationObserver { // infrastructure goes away. void Shutdown(); + // Returns the externally visible state and corresponding error details. + PolicySubsystemState state(); + ErrorDetails error_details(); + + // Stops all auto-retrying error handling behavior inside the policy + // subsystem. + void StopAutoRetry(); + ConfigurationPolicyProvider* GetManagedPolicyProvider(); ConfigurationPolicyProvider* GetRecommendedPolicyProvider(); @@ -50,6 +96,11 @@ class CloudPolicySubsystem : public NotificationObserver { // Updates the policy controller with a new refresh rate value. void UpdatePolicyRefreshRate(); + // Returns a weak pointer to this subsystem's PolicyNotifier. + PolicyNotifier* notifier() { + return notifier_.get(); + } + // NotificationObserver overrides. virtual void Observe(NotificationType type, const NotificationSource& source, @@ -62,6 +113,7 @@ class CloudPolicySubsystem : public NotificationObserver { IntegerPrefMember policy_refresh_rate_; // Cloud policy infrastructure stuff. + scoped_ptr<PolicyNotifier> notifier_; scoped_ptr<DeviceManagementService> device_management_service_; scoped_ptr<DeviceTokenFetcher> device_token_fetcher_; scoped_ptr<CloudPolicyCacheBase> cloud_policy_cache_; diff --git a/chrome/browser/policy/device_management_backend_impl.cc b/chrome/browser/policy/device_management_backend_impl.cc index bc95c12..7accf7b 100644 --- a/chrome/browser/policy/device_management_backend_impl.cc +++ b/chrome/browser/policy/device_management_backend_impl.cc @@ -48,7 +48,7 @@ const int kDeviceManagementNotAllowed = 403; const int kInvalidURL = 404; // This error is not coming from the GFE. const int kPendingApproval = 491; const int kInternalServerError = 500; -const int kServiceUnavaiable = 503; +const int kServiceUnavailable = 503; const int kDeviceNotFound = 901; const int kPolicyNotFound = 902; // This error is not sent as HTTP status code. @@ -215,7 +215,7 @@ void DeviceManagementJobBase::HandleResponse( } case kInvalidURL: case kInternalServerError: - case kServiceUnavaiable: { + case kServiceUnavailable: { OnError(DeviceManagementBackend::kErrorTemporaryUnavailable); return; } diff --git a/chrome/browser/policy/device_policy_cache.cc b/chrome/browser/policy/device_policy_cache.cc index 39381dc..bbd780f 100644 --- a/chrome/browser/policy/device_policy_cache.cc +++ b/chrome/browser/policy/device_policy_cache.cc @@ -9,6 +9,7 @@ #include "base/task.h" #include "base/values.h" #include "chrome/browser/policy/configuration_policy_pref_store.h" +#include "chrome/browser/policy/device_policy_identity_strategy.h" #include "chrome/browser/policy/policy_map.h" #include "chrome/browser/policy/proto/cloud_policy.pb.h" #include "chrome/browser/policy/proto/device_management_constants.h" @@ -20,13 +21,19 @@ using google::protobuf::RepeatedPtrField; namespace policy { -DevicePolicyCache::DevicePolicyCache() - : signed_settings_helper_(chromeos::SignedSettingsHelper::Get()) { +DevicePolicyCache::DevicePolicyCache( + DevicePolicyIdentityStrategy* identity_strategy) + : identity_strategy_(identity_strategy), + signed_settings_helper_(chromeos::SignedSettingsHelper::Get()), + starting_up_(true) { } DevicePolicyCache::DevicePolicyCache( + DevicePolicyIdentityStrategy* identity_strategy, chromeos::SignedSettingsHelper* signed_settings_helper) - : signed_settings_helper_(signed_settings_helper) { + : identity_strategy_(identity_strategy), + signed_settings_helper_(signed_settings_helper), + starting_up_(true) { } DevicePolicyCache::~DevicePolicyCache() { @@ -34,13 +41,11 @@ DevicePolicyCache::~DevicePolicyCache() { } void DevicePolicyCache::Load() { - // TODO(jkummerow): check if we're unmanaged; if so, set is_unmanaged_ = true - // and return immediately. - signed_settings_helper_->StartRetrievePolicyOp(this); } void DevicePolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) { + DCHECK(!starting_up_); set_last_policy_refresh_time(base::Time::NowFromSystemTime()); signed_settings_helper_->StartStorePolicyOp(policy, this); } @@ -54,23 +59,71 @@ void DevicePolicyCache::OnRetrievePolicyCompleted( chromeos::SignedSettings::ReturnCode code, const em::PolicyFetchResponse& policy) { DCHECK(CalledOnValidThread()); - if (code != chromeos::SignedSettings::SUCCESS) { - // TODO(jkummerow): We can't really do anything about this error, but - // we may want to notify the user that something is wrong. - return; + if (starting_up_) { + starting_up_ = false; + if (code == chromeos::SignedSettings::NOT_FOUND || + code == chromeos::SignedSettings::KEY_UNAVAILABLE || + !policy.has_policy_data()) { + InformNotifier(CloudPolicySubsystem::UNENROLLED, + CloudPolicySubsystem::NO_DETAILS); + return; + } + em::PolicyData policy_data; + if (!policy_data.ParseFromString(policy.policy_data())) { + LOG(WARNING) << "Failed to parse PolicyData protobuf."; + InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, + CloudPolicySubsystem::POLICY_LOCAL_ERROR); + return; + } + if (!policy_data.has_request_token() || + policy_data.request_token().empty()) { + SetUnmanagedInternal(base::Time::NowFromSystemTime()); + InformNotifier(CloudPolicySubsystem::UNMANAGED, + CloudPolicySubsystem::NO_DETAILS); + // TODO(jkummerow): Reminder: When we want to feed device-wide settings + // made by a local owner into this cache, we need to call + // SetPolicyInternal() here. + return; + } + if (!policy_data.has_username() || !policy_data.has_device_id()) { + InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, + CloudPolicySubsystem::POLICY_LOCAL_ERROR); + return; + } + identity_strategy_->SetDeviceManagementCredentials( + policy_data.username(), + policy_data.device_id(), + policy_data.request_token()); + SetPolicyInternal(policy, NULL, false); + } else { // In other words, starting_up_ == false. + if (code != chromeos::SignedSettings::SUCCESS) { + if (code == chromeos::SignedSettings::BAD_SIGNATURE) { + InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, + CloudPolicySubsystem::SIGNATURE_MISMATCH); + } else { + InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, + CloudPolicySubsystem::POLICY_LOCAL_ERROR); + } + return; + } + SetPolicyInternal(policy, NULL, false); } - SetPolicyInternal(policy, NULL, false); } void DevicePolicyCache::OnStorePolicyCompleted( chromeos::SignedSettings::ReturnCode code) { DCHECK(CalledOnValidThread()); if (code != chromeos::SignedSettings::SUCCESS) { - // TODO(jkummerow): We can't really do anything about this error, but - // we may want to notify the user that something is wrong. + if (code == chromeos::SignedSettings::BAD_SIGNATURE) { + InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, + CloudPolicySubsystem::SIGNATURE_MISMATCH); + } else { + InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, + CloudPolicySubsystem::POLICY_LOCAL_ERROR); + } return; } - Load(); + signed_settings_helper_->StartRetrievePolicyOp(this); } bool DevicePolicyCache::DecodePolicyData(const em::PolicyData& policy_data, diff --git a/chrome/browser/policy/device_policy_cache.h b/chrome/browser/policy/device_policy_cache.h index f6a9514..021cffc 100644 --- a/chrome/browser/policy/device_policy_cache.h +++ b/chrome/browser/policy/device_policy_cache.h @@ -15,6 +15,7 @@ namespace policy { +class DevicePolicyIdentityStrategy; class PolicyMap; namespace em = enterprise_management; @@ -24,7 +25,7 @@ namespace em = enterprise_management; class DevicePolicyCache : public CloudPolicyCacheBase, public chromeos::SignedSettingsHelper::Callback { public: - DevicePolicyCache(); + explicit DevicePolicyCache(DevicePolicyIdentityStrategy* identity_strategy); virtual ~DevicePolicyCache(); // CloudPolicyCacheBase implementation: @@ -44,7 +45,8 @@ class DevicePolicyCache : public CloudPolicyCacheBase, // Alternate c'tor allowing tests to mock out the SignedSettingsHelper // singleton. - explicit DevicePolicyCache( + DevicePolicyCache( + DevicePolicyIdentityStrategy* identity_strategy, chromeos::SignedSettingsHelper* signed_settings_helper); // CloudPolicyCacheBase implementation: @@ -56,8 +58,12 @@ class DevicePolicyCache : public CloudPolicyCacheBase, PolicyMap* mandatory, PolicyMap* recommended); + DevicePolicyIdentityStrategy* identity_strategy_; + chromeos::SignedSettingsHelper* signed_settings_helper_; + bool starting_up_; + DISALLOW_COPY_AND_ASSIGN(DevicePolicyCache); }; diff --git a/chrome/browser/policy/device_policy_cache_unittest.cc b/chrome/browser/policy/device_policy_cache_unittest.cc index 79c2c82..4228470 100644 --- a/chrome/browser/policy/device_policy_cache_unittest.cc +++ b/chrome/browser/policy/device_policy_cache_unittest.cc @@ -4,6 +4,7 @@ #include "chrome/browser/policy/device_policy_cache.h" +#include "chrome/browser/policy/device_policy_identity_strategy.h" #include "policy/configuration_policy_type.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -77,7 +78,8 @@ class DevicePolicyCacheTest : public testing::Test { } virtual void SetUp() { - cache_.reset(new DevicePolicyCache(&signed_settings_helper_)); + cache_.reset(new DevicePolicyCache(&identity_strategy_, + &signed_settings_helper_)); } virtual void TearDown() { @@ -90,6 +92,7 @@ class DevicePolicyCacheTest : public testing::Test { } scoped_ptr<DevicePolicyCache> cache_; + DevicePolicyIdentityStrategy identity_strategy_; MockSignedSettingsHelper signed_settings_helper_; private: diff --git a/chrome/browser/policy/device_policy_identity_strategy.cc b/chrome/browser/policy/device_policy_identity_strategy.cc index 82b5303..010ca90 100644 --- a/chrome/browser/policy/device_policy_identity_strategy.cc +++ b/chrome/browser/policy/device_policy_identity_strategy.cc @@ -18,105 +18,12 @@ namespace policy { -// Responsible for querying device ownership on the FILE thread. -class DevicePolicyIdentityStrategy::OwnershipChecker - : public base::RefCountedThreadSafe< - DevicePolicyIdentityStrategy::OwnershipChecker> { - public: - explicit OwnershipChecker( - const base::WeakPtr<DevicePolicyIdentityStrategy>& strategy) - : strategy_(strategy) {} - - // Initiates a query on the file thread to check if the currently logged in - // user is the owner. - void CheckCurrentUserIsOwner(); - - private: - void CheckOnFileThread(); - void CallbackOnUIThread(bool current_user_is_owner); - - private: - friend class base::RefCountedThreadSafe<OwnershipChecker>; - - ~OwnershipChecker() {} - - // The object to be called back with the result. - base::WeakPtr<DevicePolicyIdentityStrategy> strategy_; - - DISALLOW_COPY_AND_ASSIGN(OwnershipChecker); -}; - -void DevicePolicyIdentityStrategy::OwnershipChecker::CheckCurrentUserIsOwner() { - if (!strategy_.get()) - return; - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - NewRunnableMethod( - this, - &DevicePolicyIdentityStrategy::OwnershipChecker::CheckOnFileThread)); -} - -void DevicePolicyIdentityStrategy::OwnershipChecker::CheckOnFileThread() { - bool current_user_is_owner = - chromeos::OwnershipService::GetSharedInstance()->CurrentUserIsOwner(); - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - NewRunnableMethod( - this, - &DevicePolicyIdentityStrategy::OwnershipChecker::CallbackOnUIThread, - current_user_is_owner)); -} - -void DevicePolicyIdentityStrategy::OwnershipChecker::CallbackOnUIThread( - bool current_user_is_owner) { - if (strategy_.get()) { - strategy_->OnOwnershipInformationAvailable(current_user_is_owner); - strategy_.reset(); - } -} - -DevicePolicyIdentityStrategy::DevicePolicyIdentityStrategy() - : current_user_is_owner_(false), - ownership_checker_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { - registrar_.Add(this, - NotificationType::TOKEN_AVAILABLE, - NotificationService::AllSources()); - registrar_.Add(this, - NotificationType::LOGIN_USER_CHANGED, - 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"; +DevicePolicyIdentityStrategy::DevicePolicyIdentityStrategy() { } DevicePolicyIdentityStrategy::~DevicePolicyIdentityStrategy() { } -void DevicePolicyIdentityStrategy::OnOwnershipInformationAvailable( - bool current_user_is_owner) { - current_user_is_owner_ = current_user_is_owner; - CheckAndTriggerFetch(); -} - -void DevicePolicyIdentityStrategy::CheckOwnershipAndTriggerFetch() { - // TODO(gfeher): Avoid firing a new query if the answer is already known. - - // Cancel any pending queries. - weak_ptr_factory_.InvalidateWeakPtrs(); - // Set to false until we know that the current user is the owner. - current_user_is_owner_ = false; - // Issue a new query. - ownership_checker_ = new OwnershipChecker(weak_ptr_factory_.GetWeakPtr()); - // The following will call back to CheckTriggerFetch(). - ownership_checker_->CheckCurrentUserIsOwner(); -} - std::string DevicePolicyIdentityStrategy::GetDeviceToken() { return device_token_; } @@ -138,27 +45,35 @@ std::string DevicePolicyIdentityStrategy::GetPolicyType() { return kChromeDevicePolicyType; } +void DevicePolicyIdentityStrategy::SetAuthCredentials( + const std::string& username, + const std::string& auth_token, + const std::string& machine_id) { + username_ = username; + auth_token_ = auth_token; + machine_id_ = machine_id; + device_id_ = guid::GenerateGUID(); + NotifyAuthChanged(); +} + +void DevicePolicyIdentityStrategy::SetDeviceManagementCredentials( + const std::string& owner_email, + const std::string& device_id, + const std::string& device_token) { + username_ = owner_email; + device_id_ = device_id; + device_token_ = device_token; + NotifyDeviceTokenChanged(); +} + bool DevicePolicyIdentityStrategy::GetCredentials(std::string* username, std::string* auth_token) { // 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 (!current_user_is_owner_) - 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); + *username = username_; + *auth_token = auth_token_; return !username->empty() && !auth_token->empty(); } @@ -171,30 +86,4 @@ void DevicePolicyIdentityStrategy::OnDeviceTokenAvailable( NotifyDeviceTokenChanged(); } -void DevicePolicyIdentityStrategy::CheckAndTriggerFetch() { - std::string username; - std::string auth_token; - if (GetCredentials(&username, &auth_token)) { - device_id_ = guid::GenerateGUID(); - 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) - CheckOwnershipAndTriggerFetch(); - } else if (type == NotificationType::LOGIN_USER_CHANGED) { - CheckOwnershipAndTriggerFetch(); - } else if (type == NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED) { - CheckOwnershipAndTriggerFetch(); - } else { - NOTREACHED(); - } -} - } // namespace policy diff --git a/chrome/browser/policy/device_policy_identity_strategy.h b/chrome/browser/policy/device_policy_identity_strategy.h index 365ed0f..2c172c3 100644 --- a/chrome/browser/policy/device_policy_identity_strategy.h +++ b/chrome/browser/policy/device_policy_identity_strategy.h @@ -8,51 +8,46 @@ #include <string> -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" +#include "base/compiler_specific.h" #include "chrome/browser/policy/cloud_policy_identity_strategy.h" -#include "content/common/notification_observer.h" -#include "content/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 { +class DevicePolicyIdentityStrategy : public CloudPolicyIdentityStrategy { public: DevicePolicyIdentityStrategy(); virtual ~DevicePolicyIdentityStrategy(); - // Called by DevicePolicyIdentityStrategy::OwnershipChecker: - virtual void OnOwnershipInformationAvailable(bool current_user_is_owner); + // Sets (GAIA) auth credentials of the owner of the device during device + // enrollment. This automatically triggers fetching a DMToken that can + // be used for future authentication with DMServer. + void SetAuthCredentials(const std::string& username, + const std::string& auth_token, + const std::string& machine_id); + + // Sets the device's credentials when they have been read from disk after + // a reboot. + void SetDeviceManagementCredentials(const std::string& owner_email, + const std::string& device_id, + const std::string& device_token); // CloudPolicyIdentityStrategy implementation: - virtual std::string GetDeviceToken(); - virtual std::string GetDeviceID(); - virtual std::string GetMachineID(); - virtual em::DeviceRegisterRequest_Type GetPolicyRegisterType(); - virtual std::string GetPolicyType(); + virtual std::string GetDeviceToken() OVERRIDE; + virtual std::string GetDeviceID() OVERRIDE; + virtual std::string GetMachineID() OVERRIDE; + virtual em::DeviceRegisterRequest_Type GetPolicyRegisterType() OVERRIDE; + virtual std::string GetPolicyType() OVERRIDE; virtual bool GetCredentials(std::string* username, - std::string* auth_token); - virtual void OnDeviceTokenAvailable(const std::string& token); + std::string* auth_token) OVERRIDE; + virtual void OnDeviceTokenAvailable(const std::string& token) OVERRIDE; private: - class OwnershipChecker; - - // Recheck whether all parameters are available and if so, trigger a - // credentials changed notification. - void CheckAndTriggerFetch(); - - // Updates the ownership information and then passes control to - // |CheckAndTriggerFetch|. - void CheckOwnershipAndTriggerFetch(); - - // NotificationObserver method overrides: - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); + // The e-mail and auth token of the device owner. Set by |SetCredentials()|. + std::string username_; + std::string auth_token_; // The machine identifier. std::string machine_id_; @@ -65,19 +60,6 @@ class DevicePolicyIdentityStrategy : public CloudPolicyIdentityStrategy, // Current token. Empty if not available. std::string device_token_; - // Whether the currently logged in user is the device's owner. This variable - // is owned by the UI thread but updated from the FILE thread. Therefore - // after an owner login it will take some time before it turns to true. - bool current_user_is_owner_; - - // Registers the provider for notification of successful Gaia logins. - NotificationRegistrar registrar_; - - scoped_refptr<OwnershipChecker> ownership_checker_; - - // Allows to construct weak ptrs. - base::WeakPtrFactory<DevicePolicyIdentityStrategy> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(DevicePolicyIdentityStrategy); }; diff --git a/chrome/browser/policy/device_token_fetcher.cc b/chrome/browser/policy/device_token_fetcher.cc index 3db1334..c1739a8 100644 --- a/chrome/browser/policy/device_token_fetcher.cc +++ b/chrome/browser/policy/device_token_fetcher.cc @@ -29,10 +29,12 @@ namespace em = enterprise_management; DeviceTokenFetcher::DeviceTokenFetcher( DeviceManagementService* service, - CloudPolicyCacheBase* cache) + CloudPolicyCacheBase* cache, + PolicyNotifier* notifier) : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { Initialize(service, cache, + notifier, kTokenFetchErrorDelayMilliseconds, kTokenFetchErrorMaxDelayMilliseconds, kUnmanagedDeviceRefreshRateMilliseconds); @@ -41,12 +43,14 @@ DeviceTokenFetcher::DeviceTokenFetcher( DeviceTokenFetcher::DeviceTokenFetcher( DeviceManagementService* service, CloudPolicyCacheBase* cache, + PolicyNotifier* notifier, int64 token_fetch_error_delay_ms, int64 token_fetch_error_max_delay_ms, int64 unmanaged_device_refresh_rate_ms) : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { Initialize(service, cache, + notifier, token_fetch_error_delay_ms, token_fetch_error_max_delay_ms, unmanaged_device_refresh_rate_ms); @@ -98,6 +102,14 @@ const std::string& DeviceTokenFetcher::GetDeviceToken() { return device_token_; } +void DeviceTokenFetcher::StopAutoRetry() { + CancelRetryTask(); + backend_.reset(); + device_token_.clear(); + auth_token_.clear(); + device_id_.clear(); +} + void DeviceTokenFetcher::AddObserver(DeviceTokenFetcher::Observer* observer) { observer_list_.AddObserver(observer); } @@ -132,7 +144,7 @@ void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) { case DeviceManagementBackend::kErrorServiceManagementTokenInvalid: // Most probably the GAIA auth cookie has expired. We can not do anything // until the user logs-in again. - SetState(STATE_INACTIVE); + SetState(STATE_BAD_AUTH); break; default: SetState(STATE_ERROR); @@ -141,11 +153,13 @@ void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) { void DeviceTokenFetcher::Initialize(DeviceManagementService* service, CloudPolicyCacheBase* cache, + PolicyNotifier* notifier, int64 token_fetch_error_delay_ms, int64 token_fetch_error_max_delay_ms, int64 unmanaged_device_refresh_rate_ms) { service_ = service; cache_ = cache; + notifier_ = notifier; token_fetch_error_delay_ms_ = token_fetch_error_delay_ms; token_fetch_error_max_delay_ms_ = token_fetch_error_max_delay_ms; effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms; @@ -168,13 +182,22 @@ void DeviceTokenFetcher::SetState(FetcherState state) { device_token_.clear(); auth_token_.clear(); device_id_.clear(); + notifier_->Inform(CloudPolicySubsystem::UNENROLLED, + CloudPolicySubsystem::NO_DETAILS, + PolicyNotifier::TOKEN_FETCHER); break; case STATE_TOKEN_AVAILABLE: FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceTokenAvailable()); + notifier_->Inform(CloudPolicySubsystem::SUCCESS, + CloudPolicySubsystem::NO_DETAILS, + PolicyNotifier::TOKEN_FETCHER); break; case STATE_UNMANAGED: delayed_work_at = cache_->last_policy_refresh_time() + base::TimeDelta::FromMilliseconds(unmanaged_device_refresh_rate_ms_); + notifier_->Inform(CloudPolicySubsystem::UNMANAGED, + CloudPolicySubsystem::NO_DETAILS, + PolicyNotifier::TOKEN_FETCHER); break; case STATE_TEMPORARY_ERROR: delayed_work_at = base::Time::Now() + @@ -183,12 +206,24 @@ void DeviceTokenFetcher::SetState(FetcherState state) { effective_token_fetch_error_delay_ms_ = std::min(effective_token_fetch_error_delay_ms_ * 2, token_fetch_error_max_delay_ms_); + notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR, + CloudPolicySubsystem::DMTOKEN_NETWORK_ERROR, + PolicyNotifier::TOKEN_FETCHER); break; case STATE_ERROR: effective_token_fetch_error_delay_ms_ = token_fetch_error_max_delay_ms_; delayed_work_at = base::Time::Now() + base::TimeDelta::FromMilliseconds( effective_token_fetch_error_delay_ms_); + notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR, + CloudPolicySubsystem::DMTOKEN_NETWORK_ERROR, + PolicyNotifier::TOKEN_FETCHER); + break; + case STATE_BAD_AUTH: + // Can't do anything, need to wait for new credentials. + notifier_->Inform(CloudPolicySubsystem::BAD_GAIA_TOKEN, + CloudPolicySubsystem::NO_DETAILS, + PolicyNotifier::TOKEN_FETCHER); break; } @@ -214,6 +249,7 @@ void DeviceTokenFetcher::ExecuteRetryTask() { case STATE_UNMANAGED: case STATE_ERROR: case STATE_TEMPORARY_ERROR: + case STATE_BAD_AUTH: FetchTokenInternal(); break; } diff --git a/chrome/browser/policy/device_token_fetcher.h b/chrome/browser/policy/device_token_fetcher.h index e010de8..cd5ddee 100644 --- a/chrome/browser/policy/device_token_fetcher.h +++ b/chrome/browser/policy/device_token_fetcher.h @@ -12,6 +12,7 @@ #include "base/observer_list.h" #include "base/task.h" #include "chrome/browser/policy/device_management_backend.h" +#include "chrome/browser/policy/policy_notifier.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" namespace policy { @@ -38,10 +39,12 @@ class DeviceTokenFetcher // |service| is used to talk to the device management service and |cache| is // used to persist whether the device is unmanaged. DeviceTokenFetcher(DeviceManagementService* service, - CloudPolicyCacheBase* cache); - // Version for tests that allows to set timing paramters. + CloudPolicyCacheBase* cache, + PolicyNotifier* notifier); + // Version for tests that allows to set timing parameters. DeviceTokenFetcher(DeviceManagementService* service, CloudPolicyCacheBase* cache, + PolicyNotifier* notifier, int64 token_fetch_error_delay_ms, int64 token_fetch_error_max_delay_ms, int64 unmanaged_device_refresh_rate_ms); @@ -60,6 +63,9 @@ class DeviceTokenFetcher // Declared virtual so it can be overridden by mocks. virtual const std::string& GetDeviceToken(); + // Disables the auto-retry-on-error behavior of this token fetcher. + void StopAutoRetry(); + void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); @@ -88,12 +94,15 @@ class DeviceTokenFetcher // Error, retry later. STATE_ERROR, // Temporary error. Retry sooner. - STATE_TEMPORARY_ERROR + STATE_TEMPORARY_ERROR, + // Server rejected the auth token. + STATE_BAD_AUTH }; // Common initialization helper. void Initialize(DeviceManagementService* service, CloudPolicyCacheBase* cache, + PolicyNotifier* notifier, int64 token_fetch_error_delay_ms, int64 token_fetch_error_max_delay_ms, int64 unmanaged_device_refresh_rate_ms); @@ -119,6 +128,8 @@ class DeviceTokenFetcher // Reference to the cache. Used to persist and read unmanaged state. CloudPolicyCacheBase* cache_; + PolicyNotifier* notifier_; + // Refresh parameters. int64 token_fetch_error_delay_ms_; int64 token_fetch_error_max_delay_ms_; diff --git a/chrome/browser/policy/device_token_fetcher_unittest.cc b/chrome/browser/policy/device_token_fetcher_unittest.cc index 2a7f9bc..2fb305e 100644 --- a/chrome/browser/policy/device_token_fetcher_unittest.cc +++ b/chrome/browser/policy/device_token_fetcher_unittest.cc @@ -11,6 +11,8 @@ #include "chrome/browser/policy/device_management_service.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" #include "chrome/browser/policy/mock_device_management_backend.h" +#include "chrome/browser/policy/mock_device_management_service.h" +#include "chrome/browser/policy/policy_notifier.h" #include "chrome/browser/policy/user_policy_cache.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/test/testing_profile.h" @@ -36,67 +38,6 @@ class MockTokenAvailableObserver : public DeviceTokenFetcher::Observer { 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); - } - - private: - DeviceManagementBackend* backend_; // weak - DISALLOW_COPY_AND_ASSIGN(ProxyDeviceManagementBackend); -}; - -DeviceManagementBackend* - MockDeviceManagementService::CreateBackend() { - return new ProxyDeviceManagementBackend(backend_); -} - class DeviceTokenFetcherTest : public testing::Test { protected: DeviceTokenFetcherTest() @@ -119,6 +60,7 @@ class DeviceTokenFetcherTest : public testing::Test { MockDeviceManagementBackend backend_; MockDeviceManagementService service_; scoped_ptr<CloudPolicyCacheBase> cache_; + PolicyNotifier notifier_; ScopedTempDir temp_user_data_dir_; private: @@ -130,7 +72,7 @@ TEST_F(DeviceTokenFetcherTest, FetchToken) { testing::InSequence s; EXPECT_CALL(backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - DeviceTokenFetcher fetcher(&service_, cache_.get()); + DeviceTokenFetcher fetcher(&service_, cache_.get(), ¬ifier_); MockTokenAvailableObserver observer; EXPECT_CALL(observer, OnDeviceTokenAvailable()); fetcher.AddObserver(&observer); @@ -162,7 +104,7 @@ TEST_F(DeviceTokenFetcherTest, RetryOnError) { MockDeviceManagementBackendFailRegister( DeviceManagementBackend::kErrorRequestFailed)).WillOnce( MockDeviceManagementBackendSucceedRegister()); - DeviceTokenFetcher fetcher(&service_, cache_.get(), 0, 0, 0); + DeviceTokenFetcher fetcher(&service_, cache_.get(), ¬ifier_, 0, 0, 0); MockTokenAvailableObserver observer; EXPECT_CALL(observer, OnDeviceTokenAvailable()); fetcher.AddObserver(&observer); @@ -179,7 +121,7 @@ TEST_F(DeviceTokenFetcherTest, UnmanagedDevice) { MockDeviceManagementBackendFailRegister( DeviceManagementBackend::kErrorServiceManagementNotSupported)); EXPECT_FALSE(cache_->is_unmanaged()); - DeviceTokenFetcher fetcher(&service_, cache_.get()); + DeviceTokenFetcher fetcher(&service_, cache_.get(), ¬ifier_); MockTokenAvailableObserver observer; EXPECT_CALL(observer, OnDeviceTokenAvailable()).Times(0); fetcher.AddObserver(&observer); diff --git a/chrome/browser/policy/mock_device_management_backend.h b/chrome/browser/policy/mock_device_management_backend.h index 8134e49..4828fdb 100644 --- a/chrome/browser/policy/mock_device_management_backend.h +++ b/chrome/browser/policy/mock_device_management_backend.h @@ -62,20 +62,6 @@ ACTION(MockDeviceManagementBackendSucceedRegister) { arg3->HandleRegisterResponse(response); } -ACTION_P2(MockDeviceManagementBackendSucceedBooleanPolicy, name, value) { - em::DevicePolicyResponse response; - em::DevicePolicySetting* setting = response.add_setting(); - setting->set_policy_key(kChromeDevicePolicySettingKey); - setting->set_watermark("fresh"); - em::GenericSetting* policy_value = setting->mutable_policy_value(); - em::GenericNamedValue* named_value = policy_value->add_named_value(); - named_value->set_name(name); - named_value->mutable_value()->set_value_type( - em::GenericValue::VALUE_TYPE_BOOL); - named_value->mutable_value()->set_bool_value(value); - arg3->HandlePolicyResponse(response); -} - ACTION(MockDeviceManagementBackendSucceedSpdyCloudPolicy) { em::PolicyData signed_response; em::CloudPolicySettings settings; diff --git a/chrome/browser/policy/mock_device_management_service.cc b/chrome/browser/policy/mock_device_management_service.cc new file mode 100644 index 0000000..f524644 --- /dev/null +++ b/chrome/browser/policy/mock_device_management_service.cc @@ -0,0 +1,50 @@ +// 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/mock_device_management_service.h" + +namespace policy { + +ProxyDeviceManagementBackend::ProxyDeviceManagementBackend( + DeviceManagementBackend* backend) + : backend_(backend) { +} +ProxyDeviceManagementBackend::~ProxyDeviceManagementBackend() {} + +void ProxyDeviceManagementBackend::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); +} + +void ProxyDeviceManagementBackend::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); +} +void ProxyDeviceManagementBackend::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); +} + +MockDeviceManagementService::MockDeviceManagementService() + : DeviceManagementService(""), + backend_(NULL) {} + +MockDeviceManagementService::~MockDeviceManagementService() {} + +DeviceManagementBackend* MockDeviceManagementService::CreateBackend() { + return new ProxyDeviceManagementBackend(backend_); +} + +} // namespace policy diff --git a/chrome/browser/policy/mock_device_management_service.h b/chrome/browser/policy/mock_device_management_service.h new file mode 100644 index 0000000..e481f1e --- /dev/null +++ b/chrome/browser/policy/mock_device_management_service.h @@ -0,0 +1,66 @@ +// 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_MOCK_DEVICE_MANAGEMENT_SERVICE_H_ +#define CHROME_BROWSER_POLICY_MOCK_DEVICE_MANAGEMENT_SERVICE_H_ +#pragma once + +#include <string> + +#include "chrome/browser/policy/device_management_backend.h" +#include "chrome/browser/policy/device_management_service.h" +#include "chrome/browser/policy/proto/device_management_backend.pb.h" + +namespace policy { + +// This proxy class is used so that expectations can be defined for a single +// persistent instance of DMBackend while the DeviceTokenFetcher under test +// merrily creates and destroys proxies. +class ProxyDeviceManagementBackend : public DeviceManagementBackend { + public: + explicit ProxyDeviceManagementBackend(DeviceManagementBackend* backend); + virtual ~ProxyDeviceManagementBackend(); + + virtual void ProcessRegisterRequest( + const std::string& auth_token, + const std::string& device_id, + const em::DeviceRegisterRequest& request, + DeviceRegisterResponseDelegate* delegate); + + virtual void ProcessUnregisterRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::DeviceUnregisterRequest& request, + DeviceUnregisterResponseDelegate* delegate); + + virtual void ProcessPolicyRequest( + const std::string& device_management_token, + const std::string& device_id, + const em::DevicePolicyRequest& request, + DevicePolicyResponseDelegate* delegate); + + private: + DeviceManagementBackend* backend_; // weak + DISALLOW_COPY_AND_ASSIGN(ProxyDeviceManagementBackend); +}; + +class MockDeviceManagementService : public DeviceManagementService { + public: + MockDeviceManagementService(); + virtual ~MockDeviceManagementService(); + + void set_backend(DeviceManagementBackend* backend) { + backend_ = backend; + } + + virtual DeviceManagementBackend* CreateBackend(); + + private: + DeviceManagementBackend* backend_; // weak + DISALLOW_COPY_AND_ASSIGN(MockDeviceManagementService); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_MOCK_DEVICE_MANAGEMENT_SERVICE_H_ diff --git a/chrome/browser/policy/policy_notifier.cc b/chrome/browser/policy/policy_notifier.cc new file mode 100644 index 0000000..23829de --- /dev/null +++ b/chrome/browser/policy/policy_notifier.cc @@ -0,0 +1,69 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/policy_notifier.h" + +namespace policy { + +void PolicyNotifier::AddObserver(CloudPolicySubsystem::Observer* observer) { + observer_list_.AddObserver(observer); +} + +void PolicyNotifier::RemoveObserver(CloudPolicySubsystem::Observer* observer) { + observer_list_.RemoveObserver(observer); +} + +PolicyNotifier::PolicyNotifier() + : state_(CloudPolicySubsystem::UNENROLLED), + error_details_(CloudPolicySubsystem::NO_DETAILS) { + for (int i = 0; i < NUM_SOURCES; ++i) { + component_states_[i] = CloudPolicySubsystem::UNENROLLED; + component_error_details_[i] = CloudPolicySubsystem::NO_DETAILS; + } +} + +PolicyNotifier::~PolicyNotifier() { +} + +void PolicyNotifier::Inform(PolicySubsystemState state, + ErrorDetails error_details, + StatusSource source) { + component_states_[source] = state; + component_error_details_[source] = error_details; + RecomputeState(); +} + +void PolicyNotifier::RecomputeState() { + // Define shortcuts. + PolicySubsystemState* s = component_states_; + ErrorDetails* e = component_error_details_; + + // Compute overall state. General idea: If any component knows we're + // unmanaged, set that as global state. Otherwise, ask components in the + // order they normally do work in. If anyone reports 'SUCCESS' or 'UNENROLLED' + // (which can also be read as 'undefined/unknown', ask the next component. + if (s[TOKEN_FETCHER] == CloudPolicySubsystem::UNMANAGED || + s[POLICY_CONTROLLER] == CloudPolicySubsystem::UNMANAGED || + s[POLICY_CACHE] == CloudPolicySubsystem::UNMANAGED) { + state_ = CloudPolicySubsystem::UNMANAGED; + error_details_ = CloudPolicySubsystem::NO_DETAILS; + } else if (s[TOKEN_FETCHER] == CloudPolicySubsystem::NETWORK_ERROR) { + state_ = s[TOKEN_FETCHER]; + error_details_ = e[TOKEN_FETCHER]; + } else if (s[TOKEN_FETCHER] == CloudPolicySubsystem::BAD_GAIA_TOKEN) { + state_ = s[TOKEN_FETCHER]; + error_details_ = e[TOKEN_FETCHER]; + } else if (s[POLICY_CONTROLLER] == CloudPolicySubsystem::NETWORK_ERROR) { + state_ = s[POLICY_CONTROLLER]; + error_details_ = e[TOKEN_FETCHER]; + } else { + state_ = s[POLICY_CACHE]; + error_details_ = e[POLICY_CACHE]; + } + + FOR_EACH_OBSERVER(CloudPolicySubsystem::Observer, observer_list_, + OnPolicyStateChanged(state_, error_details_)); +} + +} // namespace policy diff --git a/chrome/browser/policy/policy_notifier.h b/chrome/browser/policy/policy_notifier.h new file mode 100644 index 0000000..a0e1062 --- /dev/null +++ b/chrome/browser/policy/policy_notifier.h @@ -0,0 +1,69 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_POLICY_NOTIFIER_H_ +#define CHROME_BROWSER_POLICY_POLICY_NOTIFIER_H_ +#pragma once + +#include "base/observer_list.h" +#include "chrome/browser/policy/cloud_policy_subsystem.h" + +namespace policy { + +// Keeps track of the state of the policy subsystem components as far as it's +// relevant to the outside world. Is informed by components about status +// changes (failures and successes), determines the overall state and +// communicates it. +class PolicyNotifier { + public: + typedef CloudPolicySubsystem::PolicySubsystemState PolicySubsystemState; + typedef CloudPolicySubsystem::ErrorDetails ErrorDetails; + + enum StatusSource { + TOKEN_FETCHER, + POLICY_CONTROLLER, + POLICY_CACHE, + NUM_SOURCES // This must be the last element in the enum. + }; + + PolicyNotifier(); + ~PolicyNotifier(); + + // Called by components of the policy subsystem. Determines the new overall + // state and triggers observer notifications as necessary. + void Inform(PolicySubsystemState state, + ErrorDetails error_details, + StatusSource source); + + CloudPolicySubsystem::PolicySubsystemState state() const { + return state_; + } + + CloudPolicySubsystem::ErrorDetails error_details() const { + return error_details_; + } + + private: + friend class CloudPolicyController; + friend class CloudPolicySubsystem::ObserverRegistrar; + + void AddObserver(CloudPolicySubsystem::Observer* observer); + void RemoveObserver(CloudPolicySubsystem::Observer* observer); + + void RecomputeState(); + + PolicySubsystemState state_; + ErrorDetails error_details_; + + PolicySubsystemState component_states_[NUM_SOURCES]; + ErrorDetails component_error_details_[NUM_SOURCES]; + + ObserverList<CloudPolicySubsystem::Observer, true> observer_list_; + + DISALLOW_COPY_AND_ASSIGN(PolicyNotifier); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_POLICY_NOTIFIER_H_ diff --git a/chrome/browser/policy/proto/device_management_backend.proto b/chrome/browser/policy/proto/device_management_backend.proto index cf6b76b..4b45f7b 100644 --- a/chrome/browser/policy/proto/device_management_backend.proto +++ b/chrome/browser/policy/proto/device_management_backend.proto @@ -204,6 +204,14 @@ message PolicyData { // was used to sign this response. Numbering should start at 1 and be // increased by 1 at each key rotation.) optional int32 public_key_version = 6; + + // The user this policy is intended for. In case of device policy, the name + // of the owner (who registered the device). + optional string username = 7; + + // In this field the DMServer should echo back the "deviceid" HTTP parameter + // from the request. + optional string device_id = 8; } message PolicyFetchResponse { diff --git a/chrome/browser/policy/user_policy_identity_strategy.cc b/chrome/browser/policy/user_policy_identity_strategy.cc index d569cd5..28bce10 100644 --- a/chrome/browser/policy/user_policy_identity_strategy.cc +++ b/chrome/browser/policy/user_policy_identity_strategy.cc @@ -178,7 +178,6 @@ std::string UserPolicyIdentityStrategy::GetPolicyType() { return kChromeUserPolicyType; } - bool UserPolicyIdentityStrategy::GetCredentials(std::string* username, std::string* auth_token) { *username = GetCurrentUser(); diff --git a/chrome/browser/policy/user_policy_identity_strategy.h b/chrome/browser/policy/user_policy_identity_strategy.h index 5c32c22..7887ade 100644 --- a/chrome/browser/policy/user_policy_identity_strategy.h +++ b/chrome/browser/policy/user_policy_identity_strategy.h @@ -31,15 +31,14 @@ class UserPolicyIdentityStrategy : public CloudPolicyIdentityStrategy, virtual ~UserPolicyIdentityStrategy(); // CloudPolicyIdentityStrategy implementation: - virtual std::string GetDeviceToken(); - virtual std::string GetDeviceID(); - virtual std::string GetMachineID(); - virtual em::DeviceRegisterRequest_Type GetPolicyRegisterType(); - virtual std::string GetPolicyType(); - + virtual std::string GetDeviceToken() OVERRIDE; + virtual std::string GetDeviceID() OVERRIDE; + virtual std::string GetMachineID() OVERRIDE; + virtual em::DeviceRegisterRequest_Type GetPolicyRegisterType() OVERRIDE; + virtual std::string GetPolicyType() OVERRIDE; virtual bool GetCredentials(std::string* username, - std::string* auth_token); - virtual void OnDeviceTokenAvailable(const std::string& token); + std::string* auth_token) OVERRIDE; + virtual void OnDeviceTokenAvailable(const std::string& token) OVERRIDE; private: class TokenCache; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 26c9e2c..f7e135d 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1529,6 +1529,8 @@ 'browser/policy/file_based_policy_provider.h', 'browser/policy/managed_prefs_banner_base.cc', 'browser/policy/managed_prefs_banner_base.h', + 'browser/policy/policy_notifier.cc', + 'browser/policy/policy_notifier.h', 'browser/policy/policy_path_parser.h', 'browser/policy/policy_path_parser_mac.mm', 'browser/policy/policy_path_parser_posix.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index ecfeb38..5bc01a4 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1451,6 +1451,8 @@ 'browser/policy/mock_configuration_policy_store.h', 'browser/policy/mock_device_management_backend.cc', 'browser/policy/mock_device_management_backend.h', + 'browser/policy/mock_device_management_service.cc', + 'browser/policy/mock_device_management_service.h', 'browser/policy/policy_map_unittest.cc', 'browser/policy/policy_path_parser_unittest.cc', 'browser/policy/user_policy_cache_unittest.cc', |