OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/files/scoped_temp_dir.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/message_loop.h" | |
10 #include "chrome/browser/policy/cloud_policy_data_store.h" | |
11 #include "chrome/browser/policy/device_token_fetcher.h" | |
12 #include "chrome/browser/policy/logging_work_scheduler.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/cloud_policy.pb.h" | |
16 #include "chrome/browser/policy/proto/device_management_backend.pb.h" | |
17 #include "chrome/browser/policy/user_policy_cache.h" | |
18 #include "content/public/test/test_browser_thread.h" | |
19 #include "policy/policy_constants.h" | |
20 #include "testing/gmock/include/gmock/gmock.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 | |
23 namespace em = enterprise_management; | |
24 | |
25 namespace policy { | |
26 | |
27 using ::testing::AnyNumber; | |
28 using ::testing::DoAll; | |
29 using ::testing::InSequence; | |
30 using ::testing::InvokeWithoutArgs; | |
31 using ::testing::_; | |
32 using content::BrowserThread; | |
33 | |
34 class MockDeviceTokenFetcher : public DeviceTokenFetcher { | |
35 public: | |
36 explicit MockDeviceTokenFetcher(CloudPolicyCacheBase* cache) | |
37 : DeviceTokenFetcher(NULL, cache, NULL, NULL) {} | |
38 virtual ~MockDeviceTokenFetcher() {} | |
39 | |
40 MOCK_METHOD0(FetchToken, void()); | |
41 MOCK_METHOD0(SetUnmanagedState, void()); | |
42 MOCK_METHOD0(SetSerialNumberInvalidState, void()); | |
43 MOCK_METHOD0(SetMissingLicensesState, void()); | |
44 | |
45 private: | |
46 DISALLOW_COPY_AND_ASSIGN(MockDeviceTokenFetcher); | |
47 }; | |
48 | |
49 class CloudPolicyControllerTest : public testing::Test { | |
50 public: | |
51 CloudPolicyControllerTest() | |
52 : ui_thread_(BrowserThread::UI, &loop_), | |
53 file_thread_(BrowserThread::FILE, &loop_) { | |
54 em::PolicyData signed_response; | |
55 em::CloudPolicySettings settings; | |
56 em::BooleanPolicyProto* spdy_proto = settings.mutable_disablespdy(); | |
57 spdy_proto->set_value(true); | |
58 spdy_proto->mutable_policy_options()->set_mode( | |
59 em::PolicyOptions::MANDATORY); | |
60 EXPECT_TRUE( | |
61 settings.SerializeToString(signed_response.mutable_policy_value())); | |
62 base::TimeDelta timestamp = | |
63 base::Time::NowFromSystemTime() - base::Time::UnixEpoch(); | |
64 signed_response.set_timestamp(timestamp.InMilliseconds()); | |
65 std::string serialized_signed_response; | |
66 EXPECT_TRUE(signed_response.SerializeToString(&serialized_signed_response)); | |
67 em::PolicyFetchResponse* fetch_response = | |
68 spdy_policy_response_.mutable_policy_response()->add_response(); | |
69 fetch_response->set_policy_data(serialized_signed_response); | |
70 } | |
71 | |
72 virtual ~CloudPolicyControllerTest() {} | |
73 | |
74 virtual void SetUp() { | |
75 ASSERT_TRUE(temp_user_data_dir_.CreateUniqueTempDir()); | |
76 cache_.reset(new UserPolicyCache( | |
77 temp_user_data_dir_.path().AppendASCII("CloudPolicyControllerTest"), | |
78 false /* wait_for_policy_fetch */)); | |
79 token_fetcher_.reset(new MockDeviceTokenFetcher(cache_.get())); | |
80 EXPECT_CALL(service_, StartJob(_, _, _, _, _, _, _)).Times(AnyNumber()); | |
81 data_store_.reset(CloudPolicyDataStore::CreateForUserPolicies()); | |
82 } | |
83 | |
84 virtual void TearDown() { | |
85 controller_.reset(); // Unregisters observers. | |
86 data_store_.reset(); | |
87 } | |
88 | |
89 void CreateNewController() { | |
90 controller_.reset(new CloudPolicyController( | |
91 &service_, cache_.get(), token_fetcher_.get(), data_store_.get(), | |
92 ¬ifier_, new DummyWorkScheduler)); | |
93 } | |
94 | |
95 void CreateNewWaitingCache() { | |
96 cache_.reset(new UserPolicyCache( | |
97 temp_user_data_dir_.path().AppendASCII("CloudPolicyControllerTest"), | |
98 true /* wait_for_policy_fetch */)); | |
99 // Make this cache's disk cache ready, but have it still waiting for a | |
100 // policy fetch. | |
101 cache_->Load(); | |
102 loop_.RunUntilIdle(); | |
103 ASSERT_TRUE(cache_->last_policy_refresh_time().is_null()); | |
104 ASSERT_FALSE(cache_->IsReady()); | |
105 } | |
106 | |
107 void ExpectHasSpdyPolicy() { | |
108 base::FundamentalValue expected(true); | |
109 ASSERT_TRUE(Value::Equals(&expected, | |
110 cache_->policy()->GetValue(key::kDisableSpdy))); | |
111 } | |
112 | |
113 protected: | |
114 scoped_ptr<CloudPolicyCacheBase> cache_; | |
115 scoped_ptr<CloudPolicyController> controller_; | |
116 scoped_ptr<MockDeviceTokenFetcher> token_fetcher_; | |
117 scoped_ptr<CloudPolicyDataStore> data_store_; | |
118 MockDeviceManagementService service_; | |
119 PolicyNotifier notifier_; | |
120 base::ScopedTempDir temp_user_data_dir_; | |
121 MessageLoop loop_; | |
122 em::DeviceManagementResponse spdy_policy_response_; | |
123 | |
124 private: | |
125 content::TestBrowserThread ui_thread_; | |
126 content::TestBrowserThread file_thread_; | |
127 | |
128 DISALLOW_COPY_AND_ASSIGN(CloudPolicyControllerTest); | |
129 }; | |
130 | |
131 // If a device token is present when the controller starts up, it should | |
132 // fetch and apply policy. | |
133 TEST_F(CloudPolicyControllerTest, StartupWithDeviceToken) { | |
134 data_store_->SetupForTesting("fake_device_token", "device_id", "", "", | |
135 true); | |
136 EXPECT_CALL(service_, | |
137 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
138 .WillOnce(DoAll(InvokeWithoutArgs(&loop_, &MessageLoop::QuitNow), | |
139 service_.SucceedJob(spdy_policy_response_))); | |
140 CreateNewController(); | |
141 loop_.RunUntilIdle(); | |
142 ExpectHasSpdyPolicy(); | |
143 } | |
144 | |
145 // If no device token is present when the controller starts up, it should | |
146 // instruct the token_fetcher_ to fetch one. | |
147 TEST_F(CloudPolicyControllerTest, StartupWithoutDeviceToken) { | |
148 data_store_->SetupForTesting("", "device_id", "a@b.com", "auth_token", | |
149 true); | |
150 EXPECT_CALL(*token_fetcher_.get(), FetchToken()).Times(1); | |
151 CreateNewController(); | |
152 loop_.RunUntilIdle(); | |
153 } | |
154 | |
155 // If the current user belongs to a known non-managed domain, no token fetch | |
156 // should be initiated. | |
157 TEST_F(CloudPolicyControllerTest, StartupUnmanagedUser) { | |
158 data_store_->SetupForTesting("", "device_id", "DannoHelper@gmail.com", | |
159 "auth_token", true); | |
160 EXPECT_CALL(*token_fetcher_.get(), FetchToken()).Times(0); | |
161 CreateNewController(); | |
162 loop_.RunUntilIdle(); | |
163 } | |
164 | |
165 // After policy has been fetched successfully, a new fetch should be triggered | |
166 // after the refresh interval has timed out. | |
167 TEST_F(CloudPolicyControllerTest, RefreshAfterSuccessfulPolicy) { | |
168 data_store_->SetupForTesting("device_token", "device_id", | |
169 "DannoHelperDelegate@b.com", | |
170 "auth_token", true); | |
171 { | |
172 InSequence s; | |
173 EXPECT_CALL(service_, | |
174 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
175 .WillOnce(service_.SucceedJob(spdy_policy_response_)); | |
176 EXPECT_CALL(service_, | |
177 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
178 .WillOnce(DoAll(InvokeWithoutArgs(&loop_, &MessageLoop::QuitNow), | |
179 service_.FailJob(DM_STATUS_REQUEST_FAILED))); | |
180 } | |
181 CreateNewController(); | |
182 loop_.RunUntilIdle(); | |
183 ExpectHasSpdyPolicy(); | |
184 } | |
185 | |
186 // If policy fetching failed, it should be retried. | |
187 TEST_F(CloudPolicyControllerTest, RefreshAfterError) { | |
188 data_store_->SetupForTesting("device_token", "device_id", | |
189 "DannoHelperDelegateImpl@b.com", | |
190 "auth_token", true); | |
191 { | |
192 InSequence s; | |
193 EXPECT_CALL(service_, | |
194 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
195 .WillOnce(service_.FailJob(DM_STATUS_REQUEST_FAILED)); | |
196 EXPECT_CALL(service_, | |
197 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
198 .WillOnce(DoAll(InvokeWithoutArgs(&loop_, &MessageLoop::QuitNow), | |
199 service_.SucceedJob(spdy_policy_response_))); | |
200 } | |
201 CreateNewController(); | |
202 loop_.RunUntilIdle(); | |
203 ExpectHasSpdyPolicy(); | |
204 } | |
205 | |
206 // If the backend reports that the device token was invalid, the controller | |
207 // should instruct the token fetcher to fetch a new token. | |
208 TEST_F(CloudPolicyControllerTest, InvalidToken) { | |
209 data_store_->SetupForTesting("device_token", "device_id", | |
210 "standup@ten.am", "auth", true); | |
211 EXPECT_CALL(service_, | |
212 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
213 .WillOnce(service_.FailJob(DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID)); | |
214 EXPECT_CALL(*token_fetcher_.get(), FetchToken()).Times(1); | |
215 CreateNewController(); | |
216 loop_.RunUntilIdle(); | |
217 } | |
218 | |
219 // If the backend reports that the device is unknown to the server, the | |
220 // controller should instruct the token fetcher to fetch a new token. | |
221 TEST_F(CloudPolicyControllerTest, DeviceNotFound) { | |
222 data_store_->SetupForTesting("device_token", "device_id", | |
223 "me@you.com", "auth", true); | |
224 EXPECT_CALL(service_, | |
225 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
226 .WillOnce(service_.FailJob(DM_STATUS_SERVICE_DEVICE_NOT_FOUND)); | |
227 EXPECT_CALL(*token_fetcher_.get(), FetchToken()).Times(1); | |
228 CreateNewController(); | |
229 loop_.RunUntilIdle(); | |
230 } | |
231 | |
232 // If the backend reports that the device-id is already existing, the | |
233 // controller should instruct the token fetcher to fetch a new token. | |
234 TEST_F(CloudPolicyControllerTest, DeviceIdConflict) { | |
235 data_store_->SetupForTesting("device_token", "device_id", | |
236 "me@you.com", "auth", true); | |
237 EXPECT_CALL(service_, | |
238 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
239 .WillOnce(service_.FailJob(DM_STATUS_SERVICE_DEVICE_ID_CONFLICT)); | |
240 EXPECT_CALL(*token_fetcher_.get(), FetchToken()).Times(1); | |
241 CreateNewController(); | |
242 loop_.RunUntilIdle(); | |
243 } | |
244 | |
245 // If the backend reports that the device is no longer managed, the controller | |
246 // should instruct the token fetcher to fetch a new token (which will in turn | |
247 // set and persist the correct 'unmanaged' state). | |
248 TEST_F(CloudPolicyControllerTest, NoLongerManaged) { | |
249 data_store_->SetupForTesting("device_token", "device_id", | |
250 "who@what.com", "auth", true); | |
251 EXPECT_CALL(service_, | |
252 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
253 .WillOnce(service_.FailJob(DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED)); | |
254 EXPECT_CALL(*token_fetcher_.get(), SetUnmanagedState()).Times(1); | |
255 CreateNewController(); | |
256 loop_.RunUntilIdle(); | |
257 } | |
258 | |
259 // If the backend reports that the device has invalid serial number, the | |
260 // controller should instruct the token fetcher not to fetch a new token | |
261 // (which will in turn set and persist the correct 'sn invalid' state). | |
262 TEST_F(CloudPolicyControllerTest, InvalidSerialNumber) { | |
263 data_store_->SetupForTesting("device_token", "device_id", | |
264 "who@what.com", "auth", true); | |
265 EXPECT_CALL(service_, | |
266 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
267 .WillOnce(service_.FailJob(DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER)); | |
268 EXPECT_CALL(*token_fetcher_.get(), SetSerialNumberInvalidState()).Times(1); | |
269 CreateNewController(); | |
270 loop_.RunUntilIdle(); | |
271 } | |
272 | |
273 // If the backend reports that the domain has run out of licenses, the | |
274 // controller should instruct the token fetcher not to fetch a new token | |
275 // (which will in turn set and persist the correct 'missing licenses' state). | |
276 TEST_F(CloudPolicyControllerTest, MissingLicenses) { | |
277 data_store_->SetupForTesting("device_token", "device_id", | |
278 "who@what.com", "auth", true); | |
279 EXPECT_CALL(service_, | |
280 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
281 .WillOnce(service_.FailJob(DM_STATUS_SERVICE_MISSING_LICENSES)); | |
282 EXPECT_CALL(*token_fetcher_.get(), SetMissingLicensesState()).Times(1); | |
283 CreateNewController(); | |
284 loop_.RunUntilIdle(); | |
285 } | |
286 | |
287 TEST_F(CloudPolicyControllerTest, DontSetFetchingDoneWithoutTokens) { | |
288 CreateNewWaitingCache(); | |
289 CreateNewController(); | |
290 // Initialized without an oauth token, goes into TOKEN_UNAVAILABLE state. | |
291 // This means the controller is still waiting for an oauth token fetch. | |
292 loop_.RunUntilIdle(); | |
293 EXPECT_FALSE(cache_->IsReady()); | |
294 | |
295 controller_->OnDeviceTokenChanged(); | |
296 loop_.RunUntilIdle(); | |
297 EXPECT_FALSE(cache_->IsReady()); | |
298 } | |
299 | |
300 TEST_F(CloudPolicyControllerTest, RefreshPoliciesWithoutMaterial) { | |
301 CreateNewWaitingCache(); | |
302 CreateNewController(); | |
303 loop_.RunUntilIdle(); | |
304 EXPECT_FALSE(cache_->IsReady()); | |
305 | |
306 // Same scenario as the last test, but the RefreshPolicies call must always | |
307 // notify the cache. | |
308 controller_->RefreshPolicies(false); | |
309 loop_.RunUntilIdle(); | |
310 EXPECT_TRUE(cache_->IsReady()); | |
311 } | |
312 | |
313 TEST_F(CloudPolicyControllerTest, DontSetFetchingDoneWithoutFetching) { | |
314 CreateNewWaitingCache(); | |
315 data_store_->SetupForTesting("device_token", "device_id", | |
316 "who@what.com", "auth", true); | |
317 CreateNewController(); | |
318 // Initialized with an oauth token, goes into TOKEN_VALID state. | |
319 // This means the controller has an oauth token and should fetch the next | |
320 // token, which is the dm server register token. | |
321 EXPECT_FALSE(cache_->IsReady()); | |
322 } | |
323 | |
324 TEST_F(CloudPolicyControllerTest, SetFetchingDoneForUnmanagedUsers) { | |
325 CreateNewWaitingCache(); | |
326 data_store_->SetupForTesting("", "device_id", | |
327 "user@gmail.com", "auth", true); | |
328 CreateNewController(); | |
329 loop_.RunUntilIdle(); | |
330 // User is in an unmanaged domain. | |
331 EXPECT_TRUE(cache_->IsReady()); | |
332 EXPECT_TRUE(cache_->last_policy_refresh_time().is_null()); | |
333 } | |
334 | |
335 TEST_F(CloudPolicyControllerTest, SetFetchingDoneAfterPolicyFetch) { | |
336 CreateNewWaitingCache(); | |
337 data_store_->SetupForTesting("device_token", "device_id", | |
338 "user@enterprise.com", "auth", true); | |
339 EXPECT_CALL(service_, | |
340 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
341 .WillOnce(DoAll(InvokeWithoutArgs(&loop_, &MessageLoop::QuitNow), | |
342 service_.SucceedJob(spdy_policy_response_))); | |
343 CreateNewController(); | |
344 loop_.RunUntilIdle(); | |
345 EXPECT_TRUE(cache_->IsReady()); | |
346 EXPECT_FALSE(cache_->last_policy_refresh_time().is_null()); | |
347 } | |
348 | |
349 TEST_F(CloudPolicyControllerTest, SetFetchingDoneAfterPolicyFetchFails) { | |
350 CreateNewWaitingCache(); | |
351 data_store_->SetupForTesting("device_token", "device_id", | |
352 "user@enterprise.com", "auth", true); | |
353 EXPECT_CALL(service_, | |
354 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
355 .WillOnce(DoAll(InvokeWithoutArgs(&loop_, &MessageLoop::QuitNow), | |
356 service_.FailJob(DM_STATUS_REQUEST_FAILED))); | |
357 CreateNewController(); | |
358 loop_.RunUntilIdle(); | |
359 EXPECT_TRUE(cache_->IsReady()); | |
360 EXPECT_TRUE(cache_->last_policy_refresh_time().is_null()); | |
361 } | |
362 | |
363 TEST_F(CloudPolicyControllerTest, DelayRefreshesIfPolicyIsInvalid) { | |
364 // Reply with a protobuf whose timestamp is too far in the future. The policy | |
365 // cache will reject it, and the controller should detect that and go into | |
366 // STATE_POLICY_ERROR instead of STATE_POLICY_VALID. | |
367 | |
368 // Build the |response|. | |
369 em::DeviceManagementResponse response; | |
370 em::PolicyData data; | |
371 em::CloudPolicySettings settings; | |
372 EXPECT_TRUE(settings.SerializeToString(data.mutable_policy_value())); | |
373 base::Time far_in_the_future = | |
374 base::Time::NowFromSystemTime() + base::TimeDelta::FromDays(42); | |
375 base::TimeDelta timestamp = far_in_the_future - base::Time::UnixEpoch(); | |
376 data.set_timestamp(timestamp.InMilliseconds()); | |
377 std::string serialized_data; | |
378 EXPECT_TRUE(data.SerializeToString(&serialized_data)); | |
379 em::PolicyFetchResponse* fetch_response = | |
380 response.mutable_policy_response()->add_response(); | |
381 fetch_response->set_policy_data(serialized_data); | |
382 | |
383 data_store_->SetupForTesting("device_token", "device_id", | |
384 "madmax@managedchrome.com", | |
385 "auth_token", true); | |
386 | |
387 EXPECT_CALL(service_, | |
388 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
389 .WillOnce(DoAll(InvokeWithoutArgs(&loop_, &MessageLoop::QuitNow), | |
390 service_.SucceedJob(response))); | |
391 CreateNewController(); | |
392 loop_.RunUntilIdle(); | |
393 EXPECT_EQ(CloudPolicySubsystem::NETWORK_ERROR, notifier_.state()); | |
394 EXPECT_EQ(CloudPolicySubsystem::POLICY_NETWORK_ERROR, | |
395 notifier_.error_details()); | |
396 } | |
397 | |
398 } // namespace policy | |
OLD | NEW |