1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/policy/cloud_policy_controller.h"
6
7#include "base/memory/scoped_temp_dir.h"
8#include "base/message_loop.h"
9#include "chrome/browser/policy/device_management_service.h"
10#include "chrome/browser/policy/device_token_fetcher.h"
11#include "chrome/browser/policy/mock_configuration_policy_store.h"
12#include "chrome/browser/policy/mock_device_management_backend.h"
13#include "chrome/browser/policy/mock_device_management_service.h"
14#include "chrome/browser/policy/policy_notifier.h"
15#include "chrome/browser/policy/proto/device_management_backend.pb.h"
16#include "chrome/browser/policy/user_policy_cache.h"
17#include "content/browser/browser_thread.h"
18#include "policy/policy_constants.h"
19#include "testing/gmock/include/gmock/gmock.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22const char kTestToken[] = "cloud_policy_controller_test_auth_token";
23
24namespace policy {
25
26namespace em = enterprise_management;
27
28using ::testing::_;
29using ::testing::AtLeast;
30using ::testing::InSequence;
31using ::testing::Mock;
32using ::testing::Return;
33
34class MockCloudPolicyIdentityStrategy : public CloudPolicyIdentityStrategy {
35 public:
36  MockCloudPolicyIdentityStrategy() {}
37  virtual ~MockCloudPolicyIdentityStrategy() {}
38
39  MOCK_METHOD0(GetDeviceToken, std::string());
40  MOCK_METHOD0(GetDeviceID, std::string());
41  MOCK_METHOD0(GetMachineID, std::string());
42  MOCK_METHOD0(GetMachineModel, std::string());
43  MOCK_METHOD0(GetPolicyType, std::string());
44  MOCK_METHOD0(GetPolicyRegisterType, em::DeviceRegisterRequest_Type());
45
46  MOCK_METHOD2(GetCredentials, bool(std::string*, std::string*));
47  virtual void OnDeviceTokenAvailable(const std::string&) {}
48
49 private:
50  DISALLOW_COPY_AND_ASSIGN(MockCloudPolicyIdentityStrategy);
51};
52
53ACTION_P2(MockCloudPolicyIdentityStrategyGetCredentials, username, auth_token) {
54  *arg0 = username;
55  *arg1 = auth_token;
56  return true;
57}
58
59class MockDeviceTokenFetcher : public DeviceTokenFetcher {
60 public:
61  explicit MockDeviceTokenFetcher(CloudPolicyCacheBase* cache)
62      : DeviceTokenFetcher(NULL, cache, NULL) {}
63  virtual ~MockDeviceTokenFetcher() {}
64
65  MOCK_METHOD0(GetDeviceToken, const std::string&());
66  MOCK_METHOD5(FetchToken,
67      void(const std::string&, const std::string&,
68           em::DeviceRegisterRequest_Type,
69           const std::string&, const std::string&));
70  MOCK_METHOD0(SetUnmanagedState, void());
71
72 private:
73  DISALLOW_COPY_AND_ASSIGN(MockDeviceTokenFetcher);
74};
75
76class CloudPolicyControllerTest : public testing::Test {
77 public:
78  CloudPolicyControllerTest()
79      : ui_thread_(BrowserThread::UI, &loop_),
80        file_thread_(BrowserThread::FILE, &loop_) {}
81
82  virtual ~CloudPolicyControllerTest() {}
83
84  virtual void SetUp() {
85    ASSERT_TRUE(temp_user_data_dir_.CreateUniqueTempDir());
86    cache_.reset(new UserPolicyCache(
87        temp_user_data_dir_.path().AppendASCII("CloudPolicyControllerTest")));
88    token_fetcher_.reset(new MockDeviceTokenFetcher(cache_.get()));
89    service_.set_backend(&backend_);
90  }
91
92  virtual void TearDown() {
93    controller_.reset();  // Unregisters observers.
94  }
95
96  // Takes ownership of |backend|.
97  void CreateNewController() {
98    controller_.reset(new CloudPolicyController(
99        &service_, cache_.get(), token_fetcher_.get(), &identity_strategy_,
100        &notifier_));
101  }
102
103  void CreateNewController(int64 policy_refresh_rate_ms,
104                           int policy_refresh_deviation_factor_percent,
105                           int64 policy_refresh_deviation_max_ms,
106                           int64 policy_refresh_error_delay_ms) {
107    controller_.reset(new CloudPolicyController(
108        &service_, cache_.get(), token_fetcher_.get(), &identity_strategy_,
109        &notifier_,
110        policy_refresh_rate_ms,
111        policy_refresh_deviation_factor_percent,
112        policy_refresh_deviation_max_ms,
113        policy_refresh_error_delay_ms));
114  }
115
116  void ExpectHasSpdyPolicy() {
117    MockConfigurationPolicyStore store;
118    EXPECT_CALL(store, Apply(_, _)).Times(AtLeast(1));
119    cache_->GetManagedPolicyProvider()->Provide(&store);
120    FundamentalValue expected(true);
121    ASSERT_TRUE(store.Get(kPolicyDisableSpdy) != NULL);
122    EXPECT_TRUE(store.Get(kPolicyDisableSpdy)->Equals(&expected));
123  }
124
125  void SetupIdentityStrategy(
126      const std::string& device_token,
127      const std::string& device_id,
128      const std::string& machine_id,
129      const std::string& machine_model,
130      const std::string& policy_type,
131      const em::DeviceRegisterRequest_Type& policy_register_type,
132      const std::string& user_name,
133      const std::string& auth_token) {
134    EXPECT_CALL(identity_strategy_, GetDeviceToken()).WillRepeatedly(
135        Return(device_token));
136    EXPECT_CALL(identity_strategy_, GetDeviceID()).WillRepeatedly(
137        Return(device_id));
138    EXPECT_CALL(identity_strategy_, GetMachineID()).WillRepeatedly(
139        Return(machine_id));
140    EXPECT_CALL(identity_strategy_, GetMachineModel()).WillRepeatedly(
141        Return(machine_model));
142    EXPECT_CALL(identity_strategy_, GetPolicyType()).WillRepeatedly(
143        Return(policy_type));
144    EXPECT_CALL(identity_strategy_, GetPolicyRegisterType()).WillRepeatedly(
145        Return(policy_register_type));
146    if (!user_name.empty()) {
147      EXPECT_CALL(identity_strategy_, GetCredentials(_, _)).WillRepeatedly(
148          MockCloudPolicyIdentityStrategyGetCredentials(user_name, auth_token));
149    }
150  }
151
152 protected:
153  scoped_ptr<CloudPolicyCacheBase> cache_;
154  scoped_ptr<CloudPolicyController> controller_;
155  scoped_ptr<MockDeviceTokenFetcher> token_fetcher_;
156  MockCloudPolicyIdentityStrategy identity_strategy_;
157  MockDeviceManagementBackend backend_;
158  MockDeviceManagementService service_;
159  PolicyNotifier notifier_;
160  ScopedTempDir temp_user_data_dir_;
161  MessageLoop loop_;
162
163 private:
164  BrowserThread ui_thread_;
165  BrowserThread file_thread_;
166
167  DISALLOW_COPY_AND_ASSIGN(CloudPolicyControllerTest);
168};
169
170// If a device token is present when the controller starts up, it should
171// fetch and apply policy.
172TEST_F(CloudPolicyControllerTest, StartupWithDeviceToken) {
173  SetupIdentityStrategy("fake_device_token", "device_id", "machine_id",
174                        "machine_model", "google/chromeos/user",
175                        em::DeviceRegisterRequest::USER, "", "");
176  EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
177      MockDeviceManagementBackendSucceedSpdyCloudPolicy());
178  CreateNewController();
179  loop_.RunAllPending();
180  ExpectHasSpdyPolicy();
181}
182
183// If no device token is present when the controller starts up, it should
184// instruct the token_fetcher_ to fetch one.
185TEST_F(CloudPolicyControllerTest, StartupWithoutDeviceToken) {
186  SetupIdentityStrategy("", "device_id", "machine_id", "machine_model",
187                        "google/chromeos/user", em::DeviceRegisterRequest::USER,
188                        "a@b.com", "auth_token");
189  EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _, _, _, _)).Times(1);
190  CreateNewController();
191  loop_.RunAllPending();
192}
193
194// If the current user belongs to a known non-managed domain, no token fetch
195// should be initiated.
196TEST_F(CloudPolicyControllerTest, StartupUnmanagedUser) {
197  SetupIdentityStrategy("", "device_id",  "machine_id", "machine_mode",
198                        "google/chromeos/user", em::DeviceRegisterRequest::USER,
199                        "DannoHelper@gmail.com", "auth_token");
200  EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _, _, _, _)).Times(0);
201  CreateNewController();
202  loop_.RunAllPending();
203}
204
205// After policy has been fetched successfully, a new fetch should be triggered
206// after the refresh interval has timed out.
207TEST_F(CloudPolicyControllerTest, RefreshAfterSuccessfulPolicy) {
208  SetupIdentityStrategy("device_token", "device_id", "machine_id",
209                        "machine_model", "google/chromeos/user",
210                        em::DeviceRegisterRequest::USER,
211                        "DannoHelperDelegate@b.com", "auth_token");
212  EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
213      MockDeviceManagementBackendSucceedSpdyCloudPolicy()).WillOnce(
214      MockDeviceManagementBackendFailPolicy(
215          DeviceManagementBackend::kErrorRequestFailed));
216  CreateNewController(0, 0, 0, 1000 * 1000);
217  loop_.RunAllPending();
218  ExpectHasSpdyPolicy();
219}
220
221// If policy fetching failed, it should be retried.
222TEST_F(CloudPolicyControllerTest, RefreshAfterError) {
223  SetupIdentityStrategy("device_token", "device_id", "machine_id",
224                        "machine_model", "google/chromeos/user",
225                        em::DeviceRegisterRequest::USER,
226                        "DannoHelperDelegateImpl@b.com", "auth_token");
227  EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
228      MockDeviceManagementBackendFailPolicy(
229          DeviceManagementBackend::kErrorRequestFailed)).WillOnce(
230      MockDeviceManagementBackendSucceedSpdyCloudPolicy());
231  CreateNewController(1000 * 1000, 0, 0, 0);
232  loop_.RunAllPending();
233  ExpectHasSpdyPolicy();
234}
235
236// If the backend reports that the device token was invalid, the controller
237// should instruct the token fetcher to fetch a new token.
238TEST_F(CloudPolicyControllerTest, InvalidToken) {
239  SetupIdentityStrategy("device_token", "device_id", "machine_id",
240                        "machine_model", "google/chromeos/user",
241                        em::DeviceRegisterRequest::USER,
242                        "standup@ten.am", "auth");
243  EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
244      MockDeviceManagementBackendFailPolicy(
245          DeviceManagementBackend::kErrorServiceManagementTokenInvalid));
246  EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _, _, _, _)).Times(1);
247  CreateNewController(1000 * 1000, 0, 0, 0);
248  loop_.RunAllPending();
249}
250
251// If the backend reports that the device is unknown to the server, the
252// controller should instruct the token fetcher to fetch a new token.
253TEST_F(CloudPolicyControllerTest, DeviceNotFound) {
254  SetupIdentityStrategy("device_token", "device_id", "machine_id",
255                        "machine_model", "google/chromeos/user",
256                        em::DeviceRegisterRequest::USER,
257                        "me@you.com", "auth");
258  EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
259      MockDeviceManagementBackendFailPolicy(
260          DeviceManagementBackend::kErrorServiceDeviceNotFound));
261  EXPECT_CALL(*token_fetcher_.get(), FetchToken(_, _, _, _, _)).Times(1);
262  CreateNewController(1000 * 1000, 0, 0, 0);
263  loop_.RunAllPending();
264}
265
266// If the backend reports that the device is no longer managed, the controller
267// should instruct the token fetcher to fetch a new token (which will in turn
268// set and persist the correct 'unmanaged' state).
269TEST_F(CloudPolicyControllerTest, NoLongerManaged) {
270  SetupIdentityStrategy("device_token", "device_id", "machine_id",
271                        "machine_model", "google/chromeos/user",
272                        em::DeviceRegisterRequest::USER,
273                        "who@what.com", "auth");
274  EXPECT_CALL(backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
275      MockDeviceManagementBackendFailPolicy(
276          DeviceManagementBackend::kErrorServiceManagementNotSupported));
277  EXPECT_CALL(*token_fetcher_.get(), SetUnmanagedState()).Times(1);
278  CreateNewController(0, 0, 0, 1000 * 1000);
279  loop_.RunAllPending();
280}
281
282}  // namespace policy
283