summaryrefslogtreecommitdiffstats
path: root/chrome/browser/policy
diff options
context:
space:
mode:
authorjkummerow@chromium.org <jkummerow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-23 12:56:17 +0000
committerjkummerow@chromium.org <jkummerow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-23 12:56:17 +0000
commitf5e942e0b0e7c5fcd84711567356280a5409a547 (patch)
tree2bc2bc899c99354f8c08e937e0bab0fc70cfdd1f /chrome/browser/policy
parentba0cb0e9bb82616fe96d16fbf65ee38aa437a633 (diff)
downloadchromium_src-f5e942e0b0e7c5fcd84711567356280a5409a547.zip
chromium_src-f5e942e0b0e7c5fcd84711567356280a5409a547.tar.gz
chromium_src-f5e942e0b0e7c5fcd84711567356280a5409a547.tar.bz2
Refresh policies from DM server periodically
Also, this takes care of retrying when policy fetching fails. BUG=62487 TEST=unit tests: DeviceManagementPolicyProviderTest.*:DeviceTokenFetcherTest.* Review URL: http://codereview.chromium.org/5219006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@67091 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/policy')
-rw-r--r--chrome/browser/policy/device_management_policy_cache.cc4
-rw-r--r--chrome/browser/policy/device_management_policy_cache.h5
-rw-r--r--chrome/browser/policy/device_management_policy_cache_unittest.cc11
-rw-r--r--chrome/browser/policy/device_management_policy_provider.cc136
-rw-r--r--chrome/browser/policy/device_management_policy_provider.h59
-rw-r--r--chrome/browser/policy/device_management_policy_provider_unittest.cc46
-rw-r--r--chrome/browser/policy/device_token_fetcher.cc25
-rw-r--r--chrome/browser/policy/device_token_fetcher.h61
-rw-r--r--chrome/browser/policy/device_token_fetcher_unittest.cc36
-rw-r--r--chrome/browser/policy/mock_device_management_backend.cc42
-rw-r--r--chrome/browser/policy/mock_device_management_backend.h8
11 files changed, 345 insertions, 88 deletions
diff --git a/chrome/browser/policy/device_management_policy_cache.cc b/chrome/browser/policy/device_management_policy_cache.cc
index d9ed7a6..534794d 100644
--- a/chrome/browser/policy/device_management_policy_cache.cc
+++ b/chrome/browser/policy/device_management_policy_cache.cc
@@ -105,9 +105,10 @@ void DeviceManagementPolicyCache::LoadPolicyFromFile() {
}
}
-void DeviceManagementPolicyCache::SetPolicy(
+bool DeviceManagementPolicyCache::SetPolicy(
const em::DevicePolicyResponse& policy) {
DictionaryValue* value = DeviceManagementPolicyCache::DecodePolicy(policy);
+ const bool new_policy_differs = !(value->Equals(policy_.get()));
base::Time now(base::Time::Now());
{
AutoLock lock(lock_);
@@ -123,6 +124,7 @@ void DeviceManagementPolicyCache::SetPolicy(
FROM_HERE,
new PersistPolicyTask(backing_file_path_, policy_copy,
base::Time::NowFromSystemTime()));
+ return new_policy_differs;
}
DictionaryValue* DeviceManagementPolicyCache::GetPolicy() {
diff --git a/chrome/browser/policy/device_management_policy_cache.h b/chrome/browser/policy/device_management_policy_cache.h
index 5136059..ffe63d4 100644
--- a/chrome/browser/policy/device_management_policy_cache.h
+++ b/chrome/browser/policy/device_management_policy_cache.h
@@ -33,8 +33,9 @@ class DeviceManagementPolicyCache {
// cache files are ignored.
void LoadPolicyFromFile();
- // Resets the policy information.
- void SetPolicy(const em::DevicePolicyResponse& policy);
+ // Resets the policy information. Returns true if the new policy is different
+ // from the previously stored policy.
+ bool SetPolicy(const em::DevicePolicyResponse& policy);
// Gets the policy information. Ownership of the return value is transferred
// to the caller.
diff --git a/chrome/browser/policy/device_management_policy_cache_unittest.cc b/chrome/browser/policy/device_management_policy_cache_unittest.cc
index 6654d38..45e78fc 100644
--- a/chrome/browser/policy/device_management_policy_cache_unittest.cc
+++ b/chrome/browser/policy/device_management_policy_cache_unittest.cc
@@ -134,7 +134,10 @@ TEST_F(DeviceManagementPolicyCacheTest, SetPolicy) {
DeviceManagementPolicyCache cache(test_file());
em::DevicePolicyResponse policy;
AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com");
- cache.SetPolicy(policy);
+ EXPECT_TRUE(cache.SetPolicy(policy));
+ em::DevicePolicyResponse policy2;
+ AddStringPolicy(&policy2, "HomepageLocation", "http://www.example.com");
+ EXPECT_FALSE(cache.SetPolicy(policy2));
DictionaryValue expected;
expected.Set("HomepageLocation",
Value::CreateStringValue("http://www.example.com"));
@@ -147,14 +150,14 @@ TEST_F(DeviceManagementPolicyCacheTest, ResetPolicy) {
em::DevicePolicyResponse policy;
AddStringPolicy(&policy, "HomepageLocation", "http://www.example.com");
- cache.SetPolicy(policy);
+ EXPECT_TRUE(cache.SetPolicy(policy));
DictionaryValue expected;
expected.Set("HomepageLocation",
Value::CreateStringValue("http://www.example.com"));
scoped_ptr<Value> policy_value(cache.GetPolicy());
EXPECT_TRUE(expected.Equals(policy_value.get()));
- cache.SetPolicy(em::DevicePolicyResponse());
+ EXPECT_TRUE(cache.SetPolicy(em::DevicePolicyResponse()));
policy_value.reset(cache.GetPolicy());
DictionaryValue empty;
EXPECT_TRUE(empty.Equals(policy_value.get()));
@@ -189,7 +192,7 @@ TEST_F(DeviceManagementPolicyCacheTest, FreshPolicyOverride) {
em::DevicePolicyResponse updated_policy;
AddStringPolicy(&updated_policy, "HomepageLocation",
"http://www.chromium.org");
- cache.SetPolicy(updated_policy);
+ EXPECT_TRUE(cache.SetPolicy(updated_policy));
cache.LoadPolicyFromFile();
DictionaryValue expected;
diff --git a/chrome/browser/policy/device_management_policy_provider.cc b/chrome/browser/policy/device_management_policy_provider.cc
index 25cfc32..f191564 100644
--- a/chrome/browser/policy/device_management_policy_provider.cc
+++ b/chrome/browser/policy/device_management_policy_provider.cc
@@ -7,12 +7,11 @@
#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 "base/time.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/policy/device_management_backend.h"
#include "chrome/browser/policy/device_management_policy_cache.h"
-#include "chrome/browser/policy/device_token_fetcher.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
@@ -22,7 +21,12 @@ namespace policy {
const char kChromePolicyScope[] = "chromeos/device";
const char kChromeDevicePolicySettingKey[] = "chrome-policy";
-const int64 kPolicyRefreshRateInMinutes = 3 * 60; // 3 hours
+const int64 kPolicyRefreshRateInMilliseconds = 3 * 60 * 60 * 1000; // 3 hours
+const int64 kPolicyRefreshMaxEarlierInMilliseconds = 20 * 60 * 1000; // 20 mins
+// 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;
// Ensures that the portion of the policy provider implementation that requires
// the IOThread is deferred until the IOThread is fully initialized. The policy
@@ -48,6 +52,22 @@ class DeviceManagementPolicyProvider::InitializeAfterIOThreadExistsTask
base::WeakPtr<DeviceManagementPolicyProvider> provider_;
};
+class DeviceManagementPolicyProvider::RefreshTask : public Task {
+ public:
+ explicit RefreshTask(base::WeakPtr<DeviceManagementPolicyProvider> provider)
+ : provider_(provider) {}
+
+ // Task implementation:
+ virtual void Run() {
+ DeviceManagementPolicyProvider* provider = provider_.get();
+ if (provider)
+ provider->RefreshTaskExecute();
+ }
+
+ private:
+ base::WeakPtr<DeviceManagementPolicyProvider> provider_;
+};
+
DeviceManagementPolicyProvider::DeviceManagementPolicyProvider(
const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list,
DeviceManagementBackend* backend,
@@ -57,7 +77,12 @@ DeviceManagementPolicyProvider::DeviceManagementPolicyProvider(
backend_(backend),
token_service_(token_service),
storage_dir_(GetOrCreateDeviceManagementDir(storage_dir)),
- policy_request_pending_(false) {
+ policy_request_pending_(false),
+ refresh_task_pending_(false),
+ policy_refresh_rate_ms_(kPolicyRefreshRateInMilliseconds),
+ policy_refresh_max_earlier_ms_(kPolicyRefreshMaxEarlierInMilliseconds),
+ policy_refresh_error_delay_ms_(kPolicyRefreshErrorDelayInMilliseconds),
+ token_fetch_error_delay_ms_(kDeviceTokenRefreshErrorDelayInMilliseconds) {
Initialize();
}
@@ -70,34 +95,46 @@ bool DeviceManagementPolicyProvider::Provide(
return true;
}
-void DeviceManagementPolicyProvider::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::DEVICE_TOKEN_AVAILABLE) {
- if (token_fetcher_.get() == Source<DeviceTokenFetcher>(source).ptr() &&
- !policy_request_pending_ &&
- IsPolicyStale()) {
- SendPolicyRequest();
- }
- } else {
- NOTREACHED();
- }
-}
-
void DeviceManagementPolicyProvider::HandlePolicyResponse(
const em::DevicePolicyResponse& response) {
- cache_->SetPolicy(response);
- NotifyStoreOfPolicyChange();
+ if (cache_->SetPolicy(response))
+ NotifyStoreOfPolicyChange();
policy_request_pending_ = false;
+ // Reset the error delay since policy fetching succeeded this time.
+ policy_refresh_error_delay_ms_ = kPolicyRefreshErrorDelayInMilliseconds;
+ ScheduleRefreshTask(GetRefreshTaskDelay());
}
void DeviceManagementPolicyProvider::OnError(
DeviceManagementBackend::ErrorCode code) {
- LOG(WARNING) << "could not provide policy from the device manager (error = "
- << code << ")";
policy_request_pending_ = false;
- // TODO(danno): do something sensible in the error case, perhaps retry later?
+ LOG(WARNING) << "Could not provide policy from the device manager (error = "
+ << code << "), will retry in "
+ << (policy_refresh_error_delay_ms_/1000) << " seconds.";
+ ScheduleRefreshTask(policy_refresh_error_delay_ms_);
+ policy_refresh_error_delay_ms_ *= 2;
+ if (policy_refresh_rate_ms_ &&
+ policy_refresh_rate_ms_ < policy_refresh_error_delay_ms_) {
+ policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_;
+ }
+}
+
+void DeviceManagementPolicyProvider::OnTokenSuccess() {
+ if (policy_request_pending_)
+ return;
+ SendPolicyRequest();
+}
+
+void DeviceManagementPolicyProvider::OnTokenError() {
+ LOG(WARNING) << "Could not retrieve device token.";
+ ScheduleRefreshTask(token_fetch_error_delay_ms_);
+ token_fetch_error_delay_ms_ *= 2;
+ if (token_fetch_error_delay_ms_ > policy_refresh_rate_ms_)
+ token_fetch_error_delay_ms_ = policy_refresh_rate_ms_;
+}
+
+void DeviceManagementPolicyProvider::OnNotManaged() {
+ VLOG(1) << "This device is not managed.";
}
void DeviceManagementPolicyProvider::Shutdown() {
@@ -107,10 +144,6 @@ void DeviceManagementPolicyProvider::Shutdown() {
}
void DeviceManagementPolicyProvider::Initialize() {
- registrar_.Add(this,
- NotificationType::DEVICE_TOKEN_AVAILABLE,
- NotificationService::AllSources());
-
const FilePath policy_path = storage_dir_.Append(
FILE_PATH_LITERAL("Policy"));
cache_.reset(new DeviceManagementPolicyCache(policy_path));
@@ -128,12 +161,15 @@ void DeviceManagementPolicyProvider::InitializeAfterIOThreadExists() {
if (token_service_) {
token_fetcher_ =
new DeviceTokenFetcher(backend_.get(), token_service_, token_path);
+ registrar_.Init(token_fetcher_);
+ registrar_.AddObserver(this);
token_fetcher_->StartFetching();
}
}
void DeviceManagementPolicyProvider::SendPolicyRequest() {
if (!policy_request_pending_) {
+ policy_request_pending_ = true;
em::DevicePolicyRequest policy_request;
policy_request.set_policy_scope(kChromePolicyScope);
em::DevicePolicySettingRequest* setting =
@@ -142,18 +178,44 @@ void DeviceManagementPolicyProvider::SendPolicyRequest() {
backend_->ProcessPolicyRequest(token_fetcher_->GetDeviceToken(),
token_fetcher_->GetDeviceID(),
policy_request, this);
- policy_request_pending_ = true;
}
}
-bool DeviceManagementPolicyProvider::IsPolicyStale() const {
- base::Time now(base::Time::NowFromSystemTime());
- base::Time last_policy_refresh_time =
- cache_->last_policy_refresh_time();
- base::Time policy_expiration_time =
- last_policy_refresh_time + base::TimeDelta::FromMinutes(
- kPolicyRefreshRateInMinutes);
- return (now > policy_expiration_time);
+void DeviceManagementPolicyProvider::RefreshTaskExecute() {
+ DCHECK(refresh_task_pending_);
+ refresh_task_pending_ = false;
+ // If there is no valid device token, the token_fetcher_ apparently failed,
+ // so it must be restarted.
+ if (!token_fetcher_->IsTokenValid()) {
+ if (token_fetcher_->IsTokenPending()) {
+ NOTREACHED();
+ return;
+ }
+ token_fetcher_->Restart();
+ return;
+ }
+ // If there is a device token, just refresh policies.
+ SendPolicyRequest();
+}
+
+void DeviceManagementPolicyProvider::ScheduleRefreshTask(
+ int64 delay_in_milliseconds) {
+ // This check is simply a safeguard, the situation currently cannot happen.
+ if (refresh_task_pending_) {
+ NOTREACHED();
+ return;
+ }
+ refresh_task_pending_ = true;
+ BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
+ new RefreshTask(AsWeakPtr()),
+ delay_in_milliseconds);
+}
+
+int64 DeviceManagementPolicyProvider::GetRefreshTaskDelay() {
+ int64 delay = policy_refresh_rate_ms_;
+ if (policy_refresh_max_earlier_ms_)
+ delay -= base::RandGenerator(policy_refresh_max_earlier_ms_);
+ return delay;
}
// static
diff --git a/chrome/browser/policy/device_management_policy_provider.h b/chrome/browser/policy/device_management_policy_provider.h
index d91e22b..89ef850 100644
--- a/chrome/browser/policy/device_management_policy_provider.h
+++ b/chrome/browser/policy/device_management_policy_provider.h
@@ -10,13 +10,11 @@
#include "base/file_path.h"
#include "base/scoped_ptr.h"
+#include "base/time.h"
#include "base/weak_ptr.h"
#include "chrome/browser/policy/configuration_policy_provider.h"
#include "chrome/browser/policy/device_management_backend.h"
-#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_source.h"
+#include "chrome/browser/policy/device_token_fetcher.h"
class TokenService;
@@ -24,16 +22,15 @@ namespace policy {
class DeviceManagementBackend;
class DeviceManagementPolicyCache;
-class DeviceTokenFetcher;
// 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 NotificationObserver,
public DeviceManagementBackend::DevicePolicyResponseDelegate,
- public base::SupportsWeakPtr<DeviceManagementPolicyProvider> {
+ public base::SupportsWeakPtr<DeviceManagementPolicyProvider>,
+ public DeviceTokenFetcher::Observer {
public:
DeviceManagementPolicyProvider(const PolicyDefinitionList* policy_list,
DeviceManagementBackend* backend,
@@ -45,16 +42,16 @@ class DeviceManagementPolicyProvider
// ConfigurationPolicyProvider implementation:
virtual bool Provide(ConfigurationPolicyStoreInterface* store);
- // NotificationObserver implementation:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
// DevicePolicyResponseDelegate implementation:
virtual void HandlePolicyResponse(
const em::DevicePolicyResponse& response);
virtual void OnError(DeviceManagementBackend::ErrorCode code);
+ // DeviceTokenFetcher::Observer implementation:
+ void OnTokenSuccess();
+ void OnTokenError();
+ void OnNotManaged();
+
// True if a policy request has been sent to the device management backend
// server and no response or error has yet been received.
bool IsPolicyRequestPending() const { return policy_request_pending_; }
@@ -65,6 +62,9 @@ class DeviceManagementPolicyProvider
private:
class InitializeAfterIOThreadExistsTask;
+ class RefreshTask;
+
+ friend class DeviceManagementPolicyProviderTest;
// Called by constructors to perform shared initialization. Initialization
// requiring the IOThread must not be performed directly in this method,
@@ -80,9 +80,15 @@ class DeviceManagementPolicyProvider
// already outstanding.
void SendPolicyRequest();
- // True if policy must be re-fetched because the cached policy is too old or
- // its time stamp is invalid.
- bool IsPolicyStale() const;
+ // Triggers policy refresh, re-requesting device token and policy information
+ // as necessary.
+ void RefreshTaskExecute();
+
+ // Schedules a new RefreshTask.
+ void ScheduleRefreshTask(int64 delay_in_milliseconds);
+
+ // Calculates when the next RefreshTask shall be executed.
+ int64 GetRefreshTaskDelay();
// Provides the URL at which requests are sent to from the device management
// backend.
@@ -93,13 +99,32 @@ class DeviceManagementPolicyProvider
static FilePath GetOrCreateDeviceManagementDir(
const FilePath& user_data_dir);
+ // Give unit tests the ability to override timeout settings.
+ void set_policy_refresh_rate_ms(int64 policy_refresh_rate_ms) {
+ policy_refresh_rate_ms_ = policy_refresh_rate_ms;
+ }
+ void set_policy_refresh_max_earlier_ms(int64 policy_refresh_max_earlier_ms) {
+ policy_refresh_max_earlier_ms_ = policy_refresh_max_earlier_ms;
+ }
+ void set_policy_refresh_error_delay_ms(int64 policy_refresh_error_delay_ms) {
+ policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms;
+ }
+ void set_token_fetch_error_delay_ms(int64 token_fetch_error_delay_ms) {
+ token_fetch_error_delay_ms_ = token_fetch_error_delay_ms;
+ }
+
scoped_ptr<DeviceManagementBackend> backend_;
- TokenService* token_service_; // weak
+ TokenService* token_service_; // weak
scoped_ptr<DeviceManagementPolicyCache> cache_;
scoped_refptr<DeviceTokenFetcher> token_fetcher_;
- NotificationRegistrar registrar_;
+ DeviceTokenFetcher::ObserverRegistrar registrar_;
FilePath storage_dir_;
bool policy_request_pending_;
+ bool refresh_task_pending_;
+ int64 policy_refresh_rate_ms_;
+ int64 policy_refresh_max_earlier_ms_;
+ int64 policy_refresh_error_delay_ms_;
+ int64 token_fetch_error_delay_ms_;
DISALLOW_COPY_AND_ASSIGN(DeviceManagementPolicyProvider);
};
diff --git a/chrome/browser/policy/device_management_policy_provider_unittest.cc b/chrome/browser/policy/device_management_policy_provider_unittest.cc
index 5717286..705b228 100644
--- a/chrome/browser/policy/device_management_policy_provider_unittest.cc
+++ b/chrome/browser/policy/device_management_policy_provider_unittest.cc
@@ -76,10 +76,21 @@ class DeviceManagementPolicyProviderTest : public testing::Test {
loop_.RunAllPending();
}
- protected:
MockDeviceManagementBackend* backend_; // weak
scoped_ptr<DeviceManagementPolicyProvider> provider_;
+ protected:
+ void SetRefreshDelays(DeviceManagementPolicyProvider* provider,
+ int64 policy_refresh_rate_ms,
+ int64 policy_refresh_max_earlier_ms,
+ int64 policy_refresh_error_delay_ms,
+ int64 token_fetch_error_delay_ms) {
+ provider->set_policy_refresh_rate_ms(policy_refresh_rate_ms);
+ provider->set_policy_refresh_max_earlier_ms(policy_refresh_max_earlier_ms);
+ provider->set_policy_refresh_error_delay_ms(policy_refresh_error_delay_ms);
+ provider->set_token_fetch_error_delay_ms(token_fetch_error_delay_ms);
+ }
+
private:
MessageLoop loop_;
BrowserThread ui_thread_;
@@ -127,13 +138,23 @@ TEST_F(DeviceManagementPolicyProviderTest, SecondProvide) {
SimulateSuccessfulInitialPolicyFetch();
// Simulate a app relaunch by constructing a new provider. Policy should be
- // immediately provided and no refresh should be triggered.
+ // refreshed (since that might be the purpose of the app relaunch).
CreateNewBackend();
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).Times(0);
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).Times(1);
CreateNewProvider();
+ Mock::VerifyAndClearExpectations(backend_);
+
+ // Simulate another app relaunch, this time against a failing backend.
+ // Cached policy should still be available.
+ CreateNewBackend();
+ backend_->AllShouldFail();
MockConfigurationPolicyStore store;
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).Times(1);
+ CreateNewProvider();
+ 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
@@ -144,9 +165,24 @@ TEST_F(DeviceManagementPolicyProviderTest, FetchTriggersRefresh) {
registrar.Add(&observer,
NotificationType::POLICY_CHANGED,
NotificationService::AllSources());
- EXPECT_CALL(observer,
- Observe(_, _, _)).Times(1);
+ EXPECT_CALL(observer, Observe(_, _, _)).Times(1);
SimulateSuccessfulInitialPolicyFetch();
}
+TEST_F(DeviceManagementPolicyProviderTest, ErrorCausesNewRequest) {
+ backend_->RegisterFailsOncePolicyFailsTwice();
+ SetRefreshDelays(provider_.get(), 1000 * 1000, 0, 0, 0);
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).Times(2);
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).Times(3);
+ SimulateSuccessfulLoginAndRunPending();
+}
+
+TEST_F(DeviceManagementPolicyProviderTest, RefreshPolicies) {
+ backend_->AllWorksFirstPolicyFailsLater();
+ SetRefreshDelays(provider_.get(), 0, 0, 1000 * 1000, 1000);
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).Times(1);
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).Times(4);
+ SimulateSuccessfulLoginAndRunPending();
}
+
+} // namespace policy
diff --git a/chrome/browser/policy/device_token_fetcher.cc b/chrome/browser/policy/device_token_fetcher.cc
index 1952747..602550f 100644
--- a/chrome/browser/policy/device_token_fetcher.cc
+++ b/chrome/browser/policy/device_token_fetcher.cc
@@ -87,11 +87,25 @@ void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) {
if (code == DeviceManagementBackend::kErrorServiceManagementNotSupported) {
device_token_ = std::string();
device_id_ = std::string();
- file_util::Delete(token_path_, false);
+ 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;
}
SetState(kStateFailure);
}
+void DeviceTokenFetcher::Restart() {
+ DCHECK(!IsTokenPending());
+ device_token_.clear();
+ device_token_load_complete_event_.Reset();
+ MakeReadyToRequestDeviceToken();
+}
+
void DeviceTokenFetcher::StartFetching() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (state_ == kStateNotStarted) {
@@ -186,12 +200,13 @@ void DeviceTokenFetcher::SetState(FetcherState state) {
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();
- NotificationService::current()->Notify(
- NotificationType::DEVICE_TOKEN_AVAILABLE,
- Source<DeviceTokenFetcher>(this),
- NotificationService::NoDetails());
+ NotifyTokenSuccess();
}
}
diff --git a/chrome/browser/policy/device_token_fetcher.h b/chrome/browser/policy/device_token_fetcher.h
index 7704d35..1bfff13 100644
--- a/chrome/browser/policy/device_token_fetcher.h
+++ b/chrome/browser/policy/device_token_fetcher.h
@@ -7,8 +7,10 @@
#pragma once
#include <string>
+#include <vector>
#include "base/file_path.h"
+#include "base/observer_list.h"
#include "base/ref_counted.h"
#include "base/waitable_event.h"
#include "chrome/browser/policy/device_management_backend.h"
@@ -31,6 +33,38 @@ class DeviceTokenFetcher
public DeviceManagementBackend::DeviceRegisterResponseDelegate,
public base::RefCountedThreadSafe<DeviceTokenFetcher> {
public:
+ class Observer {
+ public:
+ virtual void OnTokenSuccess() = 0;
+ virtual void OnTokenError() = 0;
+ virtual void OnNotManaged() = 0;
+ virtual ~Observer() {}
+ };
+
+ class ObserverRegistrar {
+ public:
+ void Init(DeviceTokenFetcher* token_fetcher) {
+ token_fetcher_ = token_fetcher;
+ }
+ ~ObserverRegistrar() {
+ RemoveAll();
+ }
+ void AddObserver(DeviceTokenFetcher::Observer* observer) {
+ observers_.push_back(observer);
+ token_fetcher_->AddObserver(observer);
+ }
+ void RemoveAll() {
+ for (std::vector<DeviceTokenFetcher::Observer*>::iterator it =
+ observers_.begin(); it != observers_.end(); ++it) {
+ token_fetcher_->RemoveObserver(*it);
+ }
+ observers_.clear();
+ }
+ 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.
@@ -49,6 +83,9 @@ class DeviceTokenFetcher
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();
@@ -87,7 +124,8 @@ class DeviceTokenFetcher
kStateReadyToRequestDeviceTokenFromServer,
kStateRequestingDeviceTokenFromServer,
kStateHasDeviceToken,
- kStateFailure
+ kStateFailure,
+ kStateNotManaged,
};
// Moves the fetcher into a new state. If the fetcher has the device token
@@ -114,6 +152,26 @@ class DeviceTokenFetcher
// available.
void SendServerRequestIfPossible();
+ void AddObserver(Observer* obs) {
+ observer_list_.AddObserver(obs);
+ }
+
+ void RemoveObserver(Observer* obs) {
+ observer_list_.RemoveObserver(obs);
+ }
+
+ void NotifyTokenSuccess() {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnTokenSuccess());
+ }
+
+ void NotifyTokenError() {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnTokenError());
+ }
+
+ void NotifyNotManaged() {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnNotManaged());
+ }
+
// 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,
@@ -124,6 +182,7 @@ class DeviceTokenFetcher
// management server and generate the device token.
static std::string GenerateNewDeviceID();
+ ObserverList<Observer, true> observer_list_;
FilePath token_path_;
DeviceManagementBackend* backend_; // weak
TokenService* token_service_;
diff --git a/chrome/browser/policy/device_token_fetcher_unittest.cc b/chrome/browser/policy/device_token_fetcher_unittest.cc
index 7546286..393195c 100644
--- a/chrome/browser/policy/device_token_fetcher_unittest.cc
+++ b/chrome/browser/policy/device_token_fetcher_unittest.cc
@@ -23,15 +23,14 @@ const char kTestToken[] = "device_token_fetcher_test_auth_token";
using testing::_;
using testing::Mock;
-class MockTokenAvailableObserver : public NotificationObserver {
+class MockTokenAvailableObserver : public DeviceTokenFetcher::Observer {
public:
MockTokenAvailableObserver() {}
virtual ~MockTokenAvailableObserver() {}
- MOCK_METHOD3(Observe, void(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details));
+ MOCK_METHOD0(OnTokenSuccess, void());
+ MOCK_METHOD0(OnTokenError, void());
+ MOCK_METHOD0(OnNotManaged, void());
private:
DISALLOW_COPY_AND_ASSIGN(MockTokenAvailableObserver);
@@ -142,12 +141,12 @@ TEST_F(DeviceTokenFetcherTest, SimpleFetchDoubleLogin) {
}
TEST_F(DeviceTokenFetcherTest, FetchBetweenBrowserLaunchAndNotify) {
- NotificationRegistrar registrar;
MockTokenAvailableObserver observer;
- registrar.Add(&observer,
- NotificationType::DEVICE_TOKEN_AVAILABLE,
- NotificationService::AllSources());
- EXPECT_CALL(observer, Observe(_, _, _)).Times(1);
+ DeviceTokenFetcher::ObserverRegistrar registrar;
+ registrar.Init(fetcher_);
+ registrar.AddObserver(&observer);
+ EXPECT_CALL(observer, OnTokenSuccess()).Times(1);
+ EXPECT_CALL(observer, OnTokenError()).Times(0);
backend_->AllShouldSucceed();
EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).Times(1);
SimulateSuccessfulLoginAndRunPending();
@@ -158,8 +157,9 @@ TEST_F(DeviceTokenFetcherTest, FetchBetweenBrowserLaunchAndNotify) {
// Swap out the fetchers, including copying the device management token on
// disk to where the new fetcher expects it.
- fetcher_ = NewTestFetcher(
- temp_user_data_dir_.path());
+ registrar.RemoveAll();
+ fetcher_ = NewTestFetcher(temp_user_data_dir_.path());
+ registrar.Init(fetcher_);
fetcher_->StartFetching();
ASSERT_TRUE(fetcher_->IsTokenPending());
loop_.RunAllPending();
@@ -170,6 +170,12 @@ TEST_F(DeviceTokenFetcherTest, FetchBetweenBrowserLaunchAndNotify) {
}
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);
backend_->AllShouldFail();
EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).Times(1);
SimulateSuccessfulLoginAndRunPending();
@@ -179,14 +185,16 @@ TEST_F(DeviceTokenFetcherTest, FailedServerRequest) {
}
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));
backend_->UnmanagedDevice();
EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).Times(1);
SimulateSuccessfulLoginAndRunPending();
ASSERT_FALSE(fetcher_->IsTokenPending());
ASSERT_EQ("", fetcher_->GetDeviceToken());
ASSERT_EQ("", device_id(fetcher_));
- FilePath token_path;
- GetDeviceTokenPath(fetcher_, &token_path);
ASSERT_FALSE(file_util::PathExists(token_path));
}
diff --git a/chrome/browser/policy/mock_device_management_backend.cc b/chrome/browser/policy/mock_device_management_backend.cc
index 05d2c3c..ca61feb 100644
--- a/chrome/browser/policy/mock_device_management_backend.cc
+++ b/chrome/browser/policy/mock_device_management_backend.cc
@@ -28,7 +28,10 @@ using em::DeviceUnregisterResponse;
using em::DevicePolicyResponse;
MockDeviceManagementBackend::MockDeviceManagementBackend()
- : DeviceManagementBackend() {
+ : DeviceManagementBackend(),
+ policy_remaining_fail_count_(0),
+ register_remaining_fail_count_(0),
+ policy_remaining_success_count_(0) {
policy_setting_ = policy_response_.add_setting();
policy_setting_->set_policy_key("chrome-policy");
policy_setting_->set_watermark("fresh");
@@ -66,6 +69,17 @@ void MockDeviceManagementBackend::UnmanagedDevice() {
&MockDeviceManagementBackend::SimulateUnmanagedRegisterRequest));
}
+void MockDeviceManagementBackend::RegisterFailsOncePolicyFailsTwice() {
+ register_remaining_fail_count_ = 1;
+ policy_remaining_fail_count_ = 2;
+ AllShouldFail();
+}
+
+void MockDeviceManagementBackend::AllWorksFirstPolicyFailsLater() {
+ policy_remaining_success_count_ = 3;
+ AllShouldSucceed();
+}
+
void MockDeviceManagementBackend::AddBooleanPolicy(const char* policy_name,
bool value) {
em::GenericSetting* policy_value = policy_setting_->mutable_policy_value();
@@ -93,6 +107,15 @@ void MockDeviceManagementBackend::SimulateSuccessfulPolicyRequest(
const std::string& device_id,
const em::DevicePolicyRequest& request,
DevicePolicyResponseDelegate* delegate) {
+ if (policy_remaining_success_count_) {
+ policy_remaining_success_count_--;
+ if (!policy_remaining_success_count_) {
+ ON_CALL(*this, ProcessPolicyRequest(_, _, _, _)).
+ WillByDefault(Invoke(
+ this,
+ &MockDeviceManagementBackend::SimulateFailedPolicyRequest));
+ }
+ }
delegate->HandlePolicyResponse(policy_response_);
}
@@ -101,6 +124,14 @@ void MockDeviceManagementBackend::SimulateFailedRegisterRequest(
const std::string& device_id,
const em::DeviceRegisterRequest& request,
DeviceRegisterResponseDelegate* delegate) {
+ if (register_remaining_fail_count_) {
+ register_remaining_fail_count_--;
+ if (!register_remaining_fail_count_) {
+ ON_CALL(*this, ProcessRegisterRequest(_, _, _, _)).WillByDefault(Invoke(
+ this,
+ &MockDeviceManagementBackend::SimulateSuccessfulRegisterRequest));
+ }
+ }
delegate->OnError(kErrorRequestFailed);
}
@@ -109,6 +140,15 @@ void MockDeviceManagementBackend::SimulateFailedPolicyRequest(
const std::string& device_id,
const em::DevicePolicyRequest& request,
DevicePolicyResponseDelegate* delegate) {
+ if (policy_remaining_fail_count_) {
+ policy_remaining_fail_count_--;
+ if (!policy_remaining_fail_count_) {
+ ON_CALL(*this, ProcessPolicyRequest(_, _, _, _)).
+ WillByDefault(Invoke(
+ this,
+ &MockDeviceManagementBackend::SimulateSuccessfulPolicyRequest));
+ }
+ }
delegate->OnError(kErrorRequestFailed);
}
diff --git a/chrome/browser/policy/mock_device_management_backend.h b/chrome/browser/policy/mock_device_management_backend.h
index 6b3258c..9371dc0 100644
--- a/chrome/browser/policy/mock_device_management_backend.h
+++ b/chrome/browser/policy/mock_device_management_backend.h
@@ -11,8 +11,8 @@
#include "base/values.h"
#include "chrome/browser/policy/device_management_backend.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace policy {
@@ -49,6 +49,8 @@ class MockDeviceManagementBackend
void AllShouldSucceed();
void AllShouldFail();
void UnmanagedDevice();
+ void RegisterFailsOncePolicyFailsTwice();
+ void AllWorksFirstPolicyFailsLater();
void SimulateSuccessfulRegisterRequest(
const std::string& auth_token,
@@ -86,6 +88,10 @@ class MockDeviceManagementBackend
em::DevicePolicyResponse policy_response_;
em::DevicePolicySetting* policy_setting_;
+ int policy_remaining_fail_count_;
+ int register_remaining_fail_count_;
+ int policy_remaining_success_count_;
+
DISALLOW_COPY_AND_ASSIGN(MockDeviceManagementBackend);
};