summaryrefslogtreecommitdiffstats
path: root/chrome/browser/policy
diff options
context:
space:
mode:
authordanno@chromium.org <danno@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-29 09:20:03 +0000
committerdanno@chromium.org <danno@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-29 09:20:03 +0000
commit2a87dce080ab4f09a180e9e6881a85ac9e8aedde (patch)
treec1d960efade31be45b7b7ba30532af14279d4bda /chrome/browser/policy
parentdc7bec0219a6d54cadf530786907bc72c6b31268 (diff)
downloadchromium_src-2a87dce080ab4f09a180e9e6881a85ac9e8aedde.zip
chromium_src-2a87dce080ab4f09a180e9e6881a85ac9e8aedde.tar.gz
chromium_src-2a87dce080ab4f09a180e9e6881a85ac9e8aedde.tar.bz2
Implement device token fetcher
First step in mechanism for fetching cloud-based policy for CrOS. BUG=none TEST=DeviceTokenFetcher* Review URL: http://codereview.chromium.org/4121003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@64388 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/policy')
-rw-r--r--chrome/browser/policy/device_management_backend.h114
-rw-r--r--chrome/browser/policy/device_token_fetcher.cc165
-rw-r--r--chrome/browser/policy/device_token_fetcher.h134
-rw-r--r--chrome/browser/policy/device_token_fetcher_unittest.cc178
-rw-r--r--chrome/browser/policy/mock_device_management_backend.cc61
-rw-r--r--chrome/browser/policy/mock_device_management_backend.h52
-rw-r--r--chrome/browser/policy/proto/device_management_backend.proto165
7 files changed, 869 insertions, 0 deletions
diff --git a/chrome/browser/policy/device_management_backend.h b/chrome/browser/policy/device_management_backend.h
new file mode 100644
index 0000000..25c7b1b
--- /dev/null
+++ b/chrome/browser/policy/device_management_backend.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_BACKEND_H_
+#define CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_BACKEND_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/non_thread_safe.h"
+#include "chrome/browser/policy/proto/device_management_backend.pb.h"
+
+namespace policy {
+
+namespace em = enterprise_management;
+
+// Interface for clients that need to converse with the device management
+// server, which provides services to register Chrome installations and CrOS
+// devices for the purpose of fetching centrally-administered policy from the
+// cloud.
+class DeviceManagementBackend : NonThreadSafe {
+ public:
+ enum ErrorCode {
+ // Request payload invalid.
+ kErrorRequestInvalid,
+ // The HTTP request failed.
+ kErrorRequestFailed,
+ // The HTTP request returned a non-success code.
+ kErrorHttpStatus,
+ // Response could not be decoded.
+ kErrorResponseDecoding,
+ // Service error: Management not supported.
+ kErrorServiceManagementNotSupported,
+ // Service error: Device not found.
+ kErrorServiceDeviceNotFound,
+ // Service error: Device token invalid.
+ kErrorServiceManagementTokenInvalid,
+ // Service error: Activation pending.
+ kErrorServiceActivationPending,
+ };
+
+ class DeviceRegisterResponseDelegate {
+ public:
+ virtual ~DeviceRegisterResponseDelegate() {}
+ virtual void HandleRegisterResponse(
+ const em::DeviceRegisterResponse& response) = 0;
+ virtual void OnError(ErrorCode code) = 0;
+
+ protected:
+ DeviceRegisterResponseDelegate() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DeviceRegisterResponseDelegate);
+ };
+
+ class DeviceUnregisterResponseDelegate {
+ public:
+ virtual ~DeviceUnregisterResponseDelegate() {}
+ virtual void HandleUnregisterResponse(
+ const em::DeviceUnregisterResponse& response) = 0;
+ virtual void OnError(ErrorCode code) = 0;
+
+ protected:
+ DeviceUnregisterResponseDelegate() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DeviceUnregisterResponseDelegate);
+ };
+
+ class DevicePolicyResponseDelegate {
+ public:
+ virtual ~DevicePolicyResponseDelegate() {}
+
+ virtual void HandlePolicyResponse(
+ const em::DevicePolicyResponse& response) = 0;
+ virtual void OnError(ErrorCode code) = 0;
+
+ protected:
+ DevicePolicyResponseDelegate() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DevicePolicyResponseDelegate);
+ };
+
+ virtual ~DeviceManagementBackend() {}
+
+ virtual void ProcessRegisterRequest(
+ const std::string& auth_token,
+ const std::string& device_id,
+ const em::DeviceRegisterRequest& request,
+ DeviceRegisterResponseDelegate* delegate) = 0;
+
+ virtual void ProcessUnregisterRequest(
+ const std::string& device_management_token,
+ const em::DeviceUnregisterRequest& request,
+ DeviceUnregisterResponseDelegate* delegate) = 0;
+
+ virtual void ProcessPolicyRequest(
+ const std::string& device_management_token,
+ const em::DevicePolicyRequest& request,
+ DevicePolicyResponseDelegate* delegate) = 0;
+
+ protected:
+ DeviceManagementBackend() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DeviceManagementBackend);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_DEVICE_MANAGEMENT_BACKEND_H_
diff --git a/chrome/browser/policy/device_token_fetcher.cc b/chrome/browser/policy/device_token_fetcher.cc
new file mode 100644
index 0000000..9362747
--- /dev/null
+++ b/chrome/browser/policy/device_token_fetcher.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/policy/device_token_fetcher.h"
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/singleton.h"
+#include "chrome/browser/net/gaia/token_service.h"
+#include "chrome/browser/policy/mock_device_management_backend.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+
+namespace {
+
+static const char kPlaceholderDeviceID[] = "placeholder_device_id";
+
+} // namespace
+
+namespace policy {
+
+bool UserDirDeviceTokenPathProvider::GetPath(FilePath* path) const {
+ FilePath dir_path;
+ if ( PathService::Get(chrome::DIR_USER_DATA, &dir_path))
+ return false;
+ *path = dir_path.Append(FILE_PATH_LITERAL("DeviceManagementToken"));
+ return true;
+}
+
+DeviceTokenFetcher::DeviceTokenFetcher(
+ DeviceManagementBackend* backend,
+ StoredDeviceTokenPathProvider* path_provider)
+ : backend_(backend),
+ path_provider_(path_provider),
+ state_(kStateLoadDeviceTokenFromDisk),
+ device_token_load_complete_event_(true, false) {
+}
+
+void DeviceTokenFetcher::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(CalledOnValidThread());
+ if (type == NotificationType::TOKEN_AVAILABLE) {
+ const Source<TokenService> token_service(source);
+ const TokenService::TokenAvailableDetails* token_details =
+ Details<const TokenService::TokenAvailableDetails>(details).ptr();
+ if (token_details->service() == GaiaConstants::kDeviceManagementService &&
+ state_ < kStateHasAuthToken) {
+ DCHECK_EQ(kStateFetchingAuthToken, state_);
+ SetState(kStateHasAuthToken);
+ em::DeviceRegisterRequest register_request;
+ backend_->ProcessRegisterRequest(token_details->token(),
+ GetDeviceID(),
+ register_request,
+ this);
+ }
+ } else {
+ NOTREACHED();
+ }
+}
+
+void DeviceTokenFetcher::HandleRegisterResponse(
+ const em::DeviceRegisterResponse& response) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(kStateHasAuthToken, state_);
+ if (response.has_device_management_token()) {
+ device_token_ = response.device_management_token();
+ FilePath device_token_path;
+ if (path_provider_->GetPath(&device_token_path)) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ NewRunnableFunction(&WriteDeviceTokenToDisk,
+ device_token_path,
+ device_token_));
+ }
+ SetState(kStateHasDeviceToken);
+ } else {
+ NOTREACHED();
+ SetState(kStateFailure);
+ }
+}
+
+void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) {
+ DCHECK(CalledOnValidThread());
+ SetState(kStateFailure);
+}
+
+void DeviceTokenFetcher::StartFetching() {
+ DCHECK(CalledOnValidThread());
+ if (state_ < kStateHasDeviceToken) {
+ FilePath device_token_path;
+ FetcherState new_state = kStateFailure;
+ if (path_provider_->GetPath(&device_token_path)) {
+ if (file_util::PathExists(device_token_path)) {
+ std::string device_token;
+ if (file_util::ReadFileToString(device_token_path, &device_token_)) {
+ new_state = kStateHasDeviceToken;
+ }
+ }
+ if (new_state != kStateHasDeviceToken) {
+ new_state = kStateFetchingAuthToken;
+ // The policy provider gets initialized with the PrefService and Profile
+ // before ServiceTokens are available. Install a notification observer
+ // to ensure that the device management token gets fetched after the
+ // AuthTokens are available if it's needed.
+ registrar_.Add(this,
+ NotificationType::TOKEN_AVAILABLE,
+ NotificationService::AllSources());
+ }
+ }
+ SetState(new_state);
+ }
+}
+
+bool DeviceTokenFetcher::IsTokenPending() {
+ DCHECK(CalledOnValidThread());
+ return !device_token_load_complete_event_.IsSignaled();
+}
+
+std::string DeviceTokenFetcher::GetDeviceToken() {
+ DCHECK(CalledOnValidThread());
+ device_token_load_complete_event_.Wait();
+ return device_token_;
+}
+
+void DeviceTokenFetcher::SetState(FetcherState state) {
+ DCHECK(CalledOnValidThread());
+ state_ = state;
+ if (state == kStateFailure) {
+ device_token_load_complete_event_.Signal();
+ } else if (state == kStateHasDeviceToken) {
+ device_token_load_complete_event_.Signal();
+ NotificationService::current()->Notify(
+ NotificationType::DEVICE_TOKEN_AVAILABLE,
+ Source<DeviceTokenFetcher>(this),
+ NotificationService::NoDetails());
+ }
+}
+
+bool DeviceTokenFetcher::IsTokenValid() const {
+ return state_ == kStateHasDeviceToken;
+}
+
+// static
+void DeviceTokenFetcher::WriteDeviceTokenToDisk(
+ const FilePath& path,
+ const std::string& device_token) {
+ file_util::WriteFile(path,
+ device_token.c_str(),
+ device_token.length());
+}
+
+// static
+std::string DeviceTokenFetcher::GetDeviceID() {
+ // TODO(danno): fetch a real device_id
+ return kPlaceholderDeviceID;
+}
+
+}
diff --git a/chrome/browser/policy/device_token_fetcher.h b/chrome/browser/policy/device_token_fetcher.h
new file mode 100644
index 0000000..f5a0770
--- /dev/null
+++ b/chrome/browser/policy/device_token_fetcher.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_POLICY_DEVICE_TOKEN_FETCHER_H_
+#define CHROME_BROWSER_POLICY_DEVICE_TOKEN_FETCHER_H_
+#pragma once
+
+#include <string>
+
+#include "base/file_path.h"
+#include "base/non_thread_safe.h"
+#include "base/waitable_event.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/browser/policy/device_management_backend.h"
+
+namespace policy {
+
+namespace em = enterprise_management;
+
+// Abstracts how the path is determined where the DeviceTokenFetcher stores the
+// device token once it has been returned from the server. Tests provide a mock
+// implementation to the DeviceTokenFetcher that doesn't write to DIR_USER_DATA.
+class StoredDeviceTokenPathProvider {
+ public:
+ virtual ~StoredDeviceTokenPathProvider() {}
+
+ // Sets |path| to contain the path at which to use to store the device
+ // management token file. Returns true if successful, otherwise false.
+ virtual bool GetPath(FilePath* path) const = 0;
+ protected:
+ StoredDeviceTokenPathProvider() {}
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StoredDeviceTokenPathProvider);
+};
+
+// Provides a path to the device token that's inside DIR_USER_DATA.
+class UserDirDeviceTokenPathProvider : public StoredDeviceTokenPathProvider {
+ public:
+ UserDirDeviceTokenPathProvider() {}
+ virtual ~UserDirDeviceTokenPathProvider() {}
+ virtual bool GetPath(FilePath* path) const;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UserDirDeviceTokenPathProvider);
+};
+
+// Fetches the device token that can be used for policy requests with the device
+// management server, either from disk if it already has been successfully
+// requested, otherwise from the device management server. An instance of the
+// fetcher is shared as a singleton by all users of the device management token
+// to ensure they all get the same token.
+class DeviceTokenFetcher
+ : public NonThreadSafe,
+ public NotificationObserver,
+ public DeviceManagementBackend::DeviceRegisterResponseDelegate {
+ public:
+ // Requests to the device management server are sent through |backend|. The
+ // DeviceTokenFetcher assumes ownership of |backend|, which is passed in
+ // explicitly to simplify mocking of the backend for unit testing. The
+ // fetcher uses |path_provider| to determine the directory in which the device
+ // token is stored once it's retrieved from the server. The fetcher assumes
+ // ownership of |path_provider|.
+ DeviceTokenFetcher(DeviceManagementBackend* backend,
+ StoredDeviceTokenPathProvider* path_provider);
+ virtual ~DeviceTokenFetcher() {}
+
+ // NotificationObserver method overrides:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // DeviceManagementBackend::DeviceRegisterResponseDelegate method overrides:
+ virtual void HandleRegisterResponse(
+ const em::DeviceRegisterResponse& response);
+ virtual void OnError(DeviceManagementBackend::ErrorCode code);
+
+ // Called by subscribers of the device management token to indicate that they
+ // will need the token in the future.
+ void StartFetching();
+
+ // Returns true if there is a pending token request to the device management
+ // server.
+ bool IsTokenPending();
+
+ // Returns the device management token for this device, blocking until
+ // outstanding requests to the device management server are satisfied. In the
+ // case that the token could not be fetched, an empty string is returned.
+ std::string GetDeviceToken();
+
+ // True if the device token has been fetched and is valid.
+ bool IsTokenValid() const;
+
+ private:
+ // The different states that the fetcher can be in during the process of
+ // getting the device token.
+ enum FetcherState {
+ kStateLoadDeviceTokenFromDisk,
+ kStateFetchingAuthToken,
+ kStateHasAuthToken,
+ kStateHasDeviceToken,
+ kStateFailure
+ };
+
+ // Moves the fetcher into a new state. If the fetcher has the device token
+ // or is moving into the failure state, callers waiting on WaitForToken
+ // are unblocked.
+ void SetState(FetcherState state);
+
+ // Saves the device management token to disk once it has been retrieved from
+ // the server. Must be called on the FILE thread.
+ static void WriteDeviceTokenToDisk(const FilePath& path,
+ const std::string& token);
+
+ // Returns the device ID used to register the device with the device
+ // management server and generate the device token.
+ static std::string GetDeviceID();
+
+ scoped_ptr<DeviceManagementBackend> backend_;
+ scoped_ptr<StoredDeviceTokenPathProvider> path_provider_;
+ FetcherState state_;
+ std::string device_token_;
+
+ // An event that is signaled only once the device token has been fetched
+ // or it has been determined that there was an error during fetching.
+ base::WaitableEvent device_token_load_complete_event_;
+
+ // Registers the fetcher for notification of successful Gaia logins.
+ NotificationRegistrar registrar_;
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_DEVICE_TOKEN_FETCHER_H_
diff --git a/chrome/browser/policy/device_token_fetcher_unittest.cc b/chrome/browser/policy/device_token_fetcher_unittest.cc
new file mode 100644
index 0000000..3d15d1b6
--- /dev/null
+++ b/chrome/browser/policy/device_token_fetcher_unittest.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/scoped_temp_dir.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/net/gaia/token_service.h"
+#include "chrome/browser/policy/device_token_fetcher.h"
+#include "chrome/browser/policy/mock_device_management_backend.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+using testing::_;
+using testing::Mock;
+
+class MockDeviceTokenPathProvider
+ : public StoredDeviceTokenPathProvider {
+ public:
+ MockDeviceTokenPathProvider() {
+ EXPECT_TRUE(temp_user_data_dir_.CreateUniqueTempDir());
+ }
+
+ virtual ~MockDeviceTokenPathProvider() {}
+
+ virtual bool GetPath(FilePath* path) const {
+ if (!file_util::PathExists(temp_user_data_dir_.path()))
+ return false;
+ *path = temp_user_data_dir_.path().Append(
+ FILE_PATH_LITERAL("temp_token_file"));
+ return true;
+ }
+
+ private:
+ ScopedTempDir temp_user_data_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDeviceTokenPathProvider);
+};
+
+class MockTokenAvailableObserver : public NotificationObserver {
+ public:
+ MockTokenAvailableObserver() {}
+ virtual ~MockTokenAvailableObserver() {}
+
+ MOCK_METHOD3(Observe, void(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockTokenAvailableObserver);
+};
+
+class DeviceTokenFetcherTest : public testing::Test {
+ protected:
+ DeviceTokenFetcherTest() {
+ backend_ = new MockDeviceManagementBackend();
+ path_provider_ = new MockDeviceTokenPathProvider();
+ fetcher_.reset(new DeviceTokenFetcher(backend_, path_provider_));
+ fetcher_->StartFetching();
+ }
+
+ virtual void SetUp() {
+ ui_thread_.reset(new BrowserThread(BrowserThread::UI, &loop_));
+ file_thread_.reset(new BrowserThread(BrowserThread::FILE, &loop_));
+ }
+
+ virtual void TearDown() {
+ loop_.RunAllPending();
+ }
+
+ void SimulateSuccessfulLogin() {
+ const std::string service(GaiaConstants::kDeviceManagementService);
+ const std::string auth_token(kFakeGaiaAuthToken);
+ const Source<TokenService> source(NULL);
+ TokenService::TokenAvailableDetails details(service, auth_token);
+ NotificationService::current()->Notify(
+ NotificationType::TOKEN_AVAILABLE,
+ source,
+ Details<const TokenService::TokenAvailableDetails>(&details));
+ loop_.RunAllPending();
+ }
+
+ MockDeviceManagementBackend* backend_; // weak
+ MockDeviceTokenPathProvider* path_provider_; // weak
+ scoped_ptr<DeviceTokenFetcher> fetcher_;
+
+ private:
+ MessageLoop loop_;
+ scoped_ptr<BrowserThread> ui_thread_;
+ scoped_ptr<BrowserThread> file_thread_;
+
+ static const char kFakeGaiaAuthToken[];
+};
+
+const char DeviceTokenFetcherTest::kFakeGaiaAuthToken[] = "0123456789abcdef";
+
+TEST_F(DeviceTokenFetcherTest, IsPending) {
+ ASSERT_TRUE(fetcher_->IsTokenPending());
+ SimulateSuccessfulLogin();
+ ASSERT_FALSE(fetcher_->IsTokenPending());
+}
+
+TEST_F(DeviceTokenFetcherTest, SimpleFetchSingleLogin) {
+ SimulateSuccessfulLogin();
+ ASSERT_FALSE(fetcher_->IsTokenPending());
+ ASSERT_TRUE(fetcher_->IsTokenValid());
+ const std::string token(fetcher_->GetDeviceToken());
+ EXPECT_NE("", token);
+}
+
+TEST_F(DeviceTokenFetcherTest, SimpleFetchDoubleLogin) {
+ SimulateSuccessfulLogin();
+ ASSERT_FALSE(fetcher_->IsTokenPending());
+ const std::string token(fetcher_->GetDeviceToken());
+ EXPECT_NE("", token);
+
+ SimulateSuccessfulLogin();
+ ASSERT_FALSE(fetcher_->IsTokenPending());
+ const std::string token2(fetcher_->GetDeviceToken());
+ EXPECT_NE("", token2);
+ EXPECT_EQ(token, token2);
+}
+
+TEST_F(DeviceTokenFetcherTest, FetchBetweenBrowserLaunchAndNotify) {
+ NotificationRegistrar registrar;
+ MockTokenAvailableObserver observer;
+ registrar.Add(&observer,
+ NotificationType::DEVICE_TOKEN_AVAILABLE,
+ NotificationService::AllSources());
+ EXPECT_CALL(observer, Observe(_, _, _)).Times(1);
+
+ SimulateSuccessfulLogin();
+ ASSERT_FALSE(fetcher_->IsTokenPending());
+ const std::string token(fetcher_->GetDeviceToken());
+ EXPECT_NE("", token);
+
+ Mock::VerifyAndClearExpectations(&observer);
+ EXPECT_CALL(observer, Observe(_, _, _)).Times(1);
+
+ // Swap out the fetchers, including copying the device management token on
+ // disk to where the new fetcher expects it.
+ backend_ = new MockDeviceManagementBackend();
+ FilePath old_path;
+ ASSERT_TRUE(path_provider_->GetPath(&old_path));
+ MockDeviceTokenPathProvider* new_provider =
+ new MockDeviceTokenPathProvider();
+ FilePath new_path;
+ ASSERT_TRUE(new_provider->GetPath(&new_path));
+ ASSERT_TRUE(file_util::Move(old_path, new_path));
+ path_provider_ = new_provider;
+ fetcher_.reset(new DeviceTokenFetcher(backend_, path_provider_));
+
+ fetcher_->StartFetching();
+ ASSERT_FALSE(fetcher_->IsTokenPending());
+ const std::string token2(fetcher_->GetDeviceToken());
+ EXPECT_NE("", token2);
+ EXPECT_EQ(token, token2);
+}
+
+TEST_F(DeviceTokenFetcherTest, FailedServerRequest) {
+ backend_->SetFailure(true);
+ SimulateSuccessfulLogin();
+ ASSERT_FALSE(fetcher_->IsTokenPending());
+ const std::string token(fetcher_->GetDeviceToken());
+ EXPECT_EQ("", token);
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/mock_device_management_backend.cc b/chrome/browser/policy/mock_device_management_backend.cc
new file mode 100644
index 0000000..61a20e9c
--- /dev/null
+++ b/chrome/browser/policy/mock_device_management_backend.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "chrome/browser/policy/mock_device_management_backend.h"
+
+namespace {
+
+static const char kFakeDeviceManagementToken[] = "FAKE_DEVICE_TOKEN_";
+static char next_token_suffix_ = '0';
+
+} // namespace
+
+namespace policy {
+
+using enterprise_management::DeviceRegisterRequest;
+using enterprise_management::DeviceUnregisterRequest;
+using enterprise_management::DevicePolicyRequest;
+using enterprise_management::DeviceRegisterResponse;
+using enterprise_management::DeviceUnregisterResponse;
+using enterprise_management::DevicePolicyResponse;
+
+MockDeviceManagementBackend::MockDeviceManagementBackend()
+ : DeviceManagementBackend(),
+ failure_(false) {
+}
+
+void MockDeviceManagementBackend::ProcessRegisterRequest(
+ const std::string& auth_token,
+ const std::string& device_id,
+ const DeviceRegisterRequest& request,
+ DeviceRegisterResponseDelegate* delegate) {
+ if (failure_) {
+ delegate->OnError(kErrorRequestInvalid);
+ } else {
+ DeviceRegisterResponse response;
+ std::string token(kFakeDeviceManagementToken);
+ token += next_token_suffix_++;
+ response.set_device_management_token(token);
+ delegate->HandleRegisterResponse(response);
+ }
+}
+
+void MockDeviceManagementBackend::ProcessUnregisterRequest(
+ const std::string& device_management_token,
+ const DeviceUnregisterRequest& request,
+ DeviceUnregisterResponseDelegate* delegate) {
+ // TODO(danno): need a mock implementation for the backend here.
+ NOTREACHED();
+}
+
+void MockDeviceManagementBackend::ProcessPolicyRequest(
+ const std::string& device_management_token,
+ const DevicePolicyRequest& request,
+ DevicePolicyResponseDelegate* delegate) {
+ // TODO(danno): need a mock implementation for the backend here.
+ NOTREACHED();
+}
+
+} // namespace
diff --git a/chrome/browser/policy/mock_device_management_backend.h b/chrome/browser/policy/mock_device_management_backend.h
new file mode 100644
index 0000000..290e615
--- /dev/null
+++ b/chrome/browser/policy/mock_device_management_backend.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_POLICY_MOCK_DEVICE_MANAGEMENT_BACKEND_H_
+#define CHROME_BROWSER_POLICY_MOCK_DEVICE_MANAGEMENT_BACKEND_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/policy/device_management_backend.h"
+
+namespace policy {
+
+namespace em = enterprise_management;
+
+// Useful for unit testing when a server-based backend isn't
+// available. Simulates both successful and failed requests to the device
+// management server.
+class MockDeviceManagementBackend
+ : public DeviceManagementBackend {
+ public:
+ MockDeviceManagementBackend();
+ virtual ~MockDeviceManagementBackend() {}
+
+ void SetFailure(bool failure) { failure_ = failure; }
+
+ // DeviceManagementBackend method overrides:
+ 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 em::DeviceUnregisterRequest& request,
+ DeviceUnregisterResponseDelegate* delegate);
+
+ virtual void ProcessPolicyRequest(
+ const std::string& device_management_token,
+ const em::DevicePolicyRequest& request,
+ DevicePolicyResponseDelegate* delegate);
+
+ private:
+ bool failure_;
+ DISALLOW_COPY_AND_ASSIGN(MockDeviceManagementBackend);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_MOCK_DEVICE_MANAGEMENT_BACKEND_H_
diff --git a/chrome/browser/policy/proto/device_management_backend.proto b/chrome/browser/policy/proto/device_management_backend.proto
new file mode 100644
index 0000000..6b0cc8d
--- /dev/null
+++ b/chrome/browser/policy/proto/device_management_backend.proto
@@ -0,0 +1,165 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package enterprise_management;
+
+// Generic value container.
+message GenericValue {
+ enum ValueType {
+ VALUE_TYPE_BOOL = 1;
+ VALUE_TYPE_INT64 = 2;
+ VALUE_TYPE_STRING = 3;
+ VALUE_TYPE_DOUBLE = 4;
+ VALUE_TYPE_BYTES = 5;
+ VALUE_TYPE_BOOL_ARRAY = 6;
+ VALUE_TYPE_INT64_ARRAY_ = 7;
+ VALUE_TYPE_STRING_ARRAY = 8;
+ VALUE_TYPE_DOUBLE_ARRAY = 9;
+ }
+
+ optional ValueType value_type = 1 [default = VALUE_TYPE_STRING];
+
+ // basic value types
+ optional bool bool_value = 2;
+ optional int64 int64_value = 3;
+ optional string string_value = 4;
+ optional double double_value = 5;
+ optional bytes bytes_value = 6;
+ repeated bool bool_array = 7;
+ repeated int64 int64_array = 8;
+ repeated string string_array = 9;
+ repeated double double_array = 10;
+}
+
+// Generic name value pair container.
+message GenericNamedValue {
+ required string name = 1;
+ optional GenericValue value = 2;
+}
+
+// A setting is a set of generic name value pairs.
+message GenericSetting {
+ repeated GenericNamedValue named_value = 1;
+}
+
+// Identify a single device policy setting key/value pair.
+message DevicePolicySetting {
+ // key of the policy setting
+ required string policy_key = 1;
+ // value of the setting
+ optional GenericSetting policy_value = 2;
+ // watermark for setting value.
+ optional string watermark = 3;
+}
+
+// Request from device to server to register device.
+message DeviceRegisterRequest {
+ // reregister device without erasing server state.
+ // it can be used to refresh dmtoken etc.
+ optional bool reregister = 1;
+}
+
+// Response from server to device register request.
+message DeviceRegisterResponse {
+ // device mangement toke for this registration.
+ required string device_management_token = 1;
+}
+
+// Request from device to server to unregister device.
+message DeviceUnregisterRequest {
+}
+
+// Response from server to device unregister request.
+message DeviceUnregisterResponse {
+}
+
+// Request for a setting or with optional watermark on client side.
+message DevicePolicySettingRequest {
+ // setting key
+ required string key = 1;
+ // watermark last read from server if available.
+ optional string watermark = 2;
+}
+
+// Request from device to server to read device policies.
+message DevicePolicyRequest {
+ // identify request scope: CrOS settings or other type of settings.
+ optional string policy_scope = 1;
+ // identify key to the settings: proxy etc.
+ repeated DevicePolicySettingRequest setting_request = 2;
+}
+
+// Response from server to agent for reading policies.
+message DevicePolicyResponse {
+ // the result of the settings.
+ repeated DevicePolicySetting setting = 1;
+}
+
+// Request from the DMAgent on the device to the DMServer.
+// This is container for all requests from client.
+//
+// Authorization:
+// 1. If request is register_request, client must pass in GoogleLogin auth
+// cookie in Authorization header:
+// Authorization: GoogleLogin auth=<auth cookie>
+// The response will contain an unique DMToken for future requests.
+// Depending on domain policy, the request may need admin approval before
+// DMToken is issued.
+// 2. For other requests, client must pass in DMToken in Authorization header:
+// Authorization: GoogleDMToken token=<google dm token>
+//
+// Http Query parameters:
+// Query parameters contain the following information in each request:
+// request: register/unregister/policy etc.
+// devicetype: CrOS/Android/Iphone etc.
+// apptype: CrOS/AndroidDM etc.
+// deviceid: unique id that identify the device.
+// agent: identify agent on device.
+message DeviceManagementRequest {
+ // Register request.
+ optional DeviceRegisterRequest register_request = 1;
+
+ // Unregister request.
+ optional DeviceUnregisterRequest unregister_request = 2;
+
+ // Data request.
+ optional DevicePolicyRequest policy_request = 3;
+}
+
+// Response from server to device.
+message DeviceManagementResponse {
+ // Error code to client.
+ enum ErrorCode {
+ SUCCESS = 0;
+ // Returned for register request when device management is not supported
+ // for the domain.
+ DEVICE_MANAGEMENT_NOT_SUPPORTED = 1;
+ // Returned when the device is not found.
+ DEVICE_NOT_FOUND = 2;
+ // Returned when passed in device management token doesn't match the token
+ // on server side.
+ DEVICE_MANAGEMENT_TOKEN_INVALID = 3;
+ // Returned when device registration is pending approval (if required).
+ ACTIVATION_PENDING = 4;
+ }
+
+ // Error code for this request.
+ required ErrorCode error = 1;
+
+ // Error message.
+ optional string error_message = 2;
+
+ // Register response
+ optional DeviceRegisterResponse register_response = 3;
+
+ // Unregister response
+ optional DeviceUnregisterResponse unregister_response = 4;
+
+ // Policy response.
+ optional DevicePolicyResponse policy_response = 5;
+}