Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(57)

Side by Side Diff: chrome/browser/policy/cloud_policy_controller.cc

Issue 11946017: Remove old cloud policy code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address nits. Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 <algorithm>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/guid.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/rand_util.h"
15 #include "chrome/browser/policy/browser_policy_connector.h"
16 #include "chrome/browser/policy/cloud_policy_cache_base.h"
17 #include "chrome/browser/policy/cloud_policy_constants.h"
18 #include "chrome/browser/policy/cloud_policy_subsystem.h"
19 #include "chrome/browser/policy/delayed_work_scheduler.h"
20 #include "chrome/browser/policy/device_management_service.h"
21 #include "chrome/browser/policy/device_token_fetcher.h"
22 #include "chrome/browser/policy/enterprise_metrics.h"
23 #include "chrome/browser/policy/policy_notifier.h"
24
25 namespace policy {
26
27 namespace {
28
29 // The maximum ratio in percent of the policy refresh rate we use for adjusting
30 // the policy refresh time instant. The rationale is to avoid load spikes from
31 // many devices that were set up in sync for some reason.
32 const int kPolicyRefreshDeviationFactorPercent = 10;
33 // Maximum deviation we are willing to accept.
34 const int64 kPolicyRefreshDeviationMaxInMilliseconds = 30 * 60 * 1000;
35
36 // These are the base values for delays before retrying after an error. They
37 // will be doubled each time they are used.
38 const int64 kPolicyRefreshErrorDelayInMilliseconds =
39 5 * 60 * 1000; // 5 minutes.
40
41 // Default value for the policy refresh rate.
42 const int kPolicyRefreshRateInMilliseconds = 3 * 60 * 60 * 1000; // 3 hours.
43
44 // Records the UMA metric corresponding to |status|, if it represents an error.
45 // Also records that a fetch response was received.
46 void SampleErrorStatus(DeviceManagementStatus status) {
47 UMA_HISTOGRAM_ENUMERATION(kMetricPolicy,
48 kMetricPolicyFetchResponseReceived,
49 kMetricPolicySize);
50 int sample = -1;
51 switch (status) {
52 case DM_STATUS_SUCCESS:
53 return;
54 case DM_STATUS_SERVICE_POLICY_NOT_FOUND:
55 sample = kMetricPolicyFetchNotFound;
56 break;
57 case DM_STATUS_SERVICE_DEVICE_NOT_FOUND:
58 sample = kMetricPolicyFetchInvalidToken;
59 break;
60 case DM_STATUS_RESPONSE_DECODING_ERROR:
61 sample = kMetricPolicyFetchBadResponse;
62 break;
63 case DM_STATUS_REQUEST_FAILED:
64 case DM_STATUS_REQUEST_INVALID:
65 case DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID:
66 sample = kMetricPolicyFetchRequestFailed;
67 break;
68 case DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED:
69 case DM_STATUS_SERVICE_DEVICE_ID_CONFLICT:
70 case DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER:
71 case DM_STATUS_TEMPORARY_UNAVAILABLE:
72 case DM_STATUS_SERVICE_ACTIVATION_PENDING:
73 case DM_STATUS_HTTP_STATUS_ERROR:
74 case DM_STATUS_SERVICE_MISSING_LICENSES:
75 sample = kMetricPolicyFetchServerFailed;
76 break;
77 }
78 if (sample != -1)
79 UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, sample, kMetricPolicySize);
80 else
81 NOTREACHED();
82 }
83
84 } // namespace
85
86 namespace em = enterprise_management;
87
88 CloudPolicyController::CloudPolicyController(
89 DeviceManagementService* service,
90 CloudPolicyCacheBase* cache,
91 DeviceTokenFetcher* token_fetcher,
92 CloudPolicyDataStore* data_store,
93 PolicyNotifier* notifier) {
94 Initialize(service,
95 cache,
96 token_fetcher,
97 data_store,
98 notifier,
99 new DelayedWorkScheduler);
100 }
101
102 CloudPolicyController::~CloudPolicyController() {
103 data_store_->RemoveObserver(this);
104 scheduler_->CancelDelayedWork();
105 }
106
107 void CloudPolicyController::SetRefreshRate(int64 refresh_rate_milliseconds) {
108 policy_refresh_rate_ms_ = refresh_rate_milliseconds;
109
110 // Reschedule the refresh task if necessary.
111 if (state_ == STATE_POLICY_VALID) {
112 scheduler_->CancelDelayedWork();
113 base::Time now(base::Time::NowFromSystemTime());
114 ScheduleDelayedWorkTask(
115 (GetLastRefreshTime(now) + GetRefreshDelay()) - now);
116 }
117 }
118
119 void CloudPolicyController::Retry() {
120 scheduler_->CancelDelayedWork();
121 DoWork();
122 }
123
124 void CloudPolicyController::Reset() {
125 SetState(STATE_TOKEN_UNAVAILABLE);
126 }
127
128 void CloudPolicyController::RefreshPolicies(bool wait_for_auth_token) {
129 // This call must eventually trigger a notification to the cache.
130 if (data_store_->device_token().empty()) {
131 // The DMToken has to be fetched.
132 if (ReadyToFetchToken()) {
133 SetState(STATE_TOKEN_UNAVAILABLE);
134 } else if (!wait_for_auth_token) {
135 // The controller doesn't have enough material to start a token fetch,
136 // but observers of the cache are waiting for the refresh.
137 SetState(STATE_TOKEN_UNMANAGED);
138 }
139 } else {
140 // The token is valid, so the next step is to fetch policy.
141 SetState(STATE_TOKEN_VALID);
142 }
143 }
144
145 void CloudPolicyController::OnPolicyFetchCompleted(
146 DeviceManagementStatus status,
147 const em::DeviceManagementResponse& response) {
148 if (status == DM_STATUS_SUCCESS && !response.has_policy_response()) {
149 // Handled below.
150 status = DM_STATUS_RESPONSE_DECODING_ERROR;
151 }
152
153 SampleErrorStatus(status);
154
155 switch (status) {
156 case DM_STATUS_SUCCESS: {
157 const em::DevicePolicyResponse& policy_response(
158 response.policy_response());
159 if (policy_response.response_size() > 0) {
160 if (policy_response.response_size() > 1) {
161 LOG(WARNING) << "More than one policy in the response of the device "
162 << "management server, discarding.";
163 }
164 const em::PolicyFetchResponse& fetch_response(
165 policy_response.response(0));
166 if (!fetch_response.has_error_code() ||
167 fetch_response.error_code() == dm_protocol::POLICY_FETCH_SUCCESS) {
168 if (cache_->SetPolicy(fetch_response))
169 SetState(STATE_POLICY_VALID);
170 else
171 SetState(STATE_POLICY_ERROR);
172 } else {
173 UMA_HISTOGRAM_ENUMERATION(kMetricPolicy,
174 kMetricPolicyFetchBadResponse,
175 kMetricPolicySize);
176 SetState(STATE_POLICY_UNAVAILABLE);
177 }
178 } else {
179 UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchBadResponse,
180 kMetricPolicySize);
181 SetState(STATE_POLICY_UNAVAILABLE);
182 }
183 return;
184 }
185 case DM_STATUS_SERVICE_DEVICE_NOT_FOUND:
186 case DM_STATUS_SERVICE_DEVICE_ID_CONFLICT:
187 case DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID:
188 LOG(WARNING) << "The device token was either invalid or unknown to the "
189 << "device manager, re-registering device.";
190 // Will retry fetching a token but gracefully backing off.
191 SetState(STATE_TOKEN_ERROR);
192 return;
193 case DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER:
194 VLOG(1) << "The device is no longer enlisted for the domain.";
195 token_fetcher_->SetSerialNumberInvalidState();
196 SetState(STATE_TOKEN_ERROR);
197 return;
198 case DM_STATUS_SERVICE_MISSING_LICENSES:
199 VLOG(1) << "There are no valid licenses for this domain left.";
200 token_fetcher_->SetMissingLicensesState();
201 SetState(STATE_TOKEN_UNMANAGED);
202 return;
203 case DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED:
204 VLOG(1) << "The device is no longer managed.";
205 token_fetcher_->SetUnmanagedState();
206 SetState(STATE_TOKEN_UNMANAGED);
207 return;
208 case DM_STATUS_SERVICE_POLICY_NOT_FOUND:
209 case DM_STATUS_REQUEST_INVALID:
210 case DM_STATUS_SERVICE_ACTIVATION_PENDING:
211 case DM_STATUS_RESPONSE_DECODING_ERROR:
212 case DM_STATUS_HTTP_STATUS_ERROR:
213 VLOG(1) << "An error in the communication with the policy server occurred"
214 << ", will retry in a few hours.";
215 SetState(STATE_POLICY_UNAVAILABLE);
216 return;
217 case DM_STATUS_REQUEST_FAILED:
218 case DM_STATUS_TEMPORARY_UNAVAILABLE:
219 VLOG(1) << "A temporary error in the communication with the policy server"
220 << " occurred.";
221 // Will retry last operation but gracefully backing off.
222 SetState(STATE_POLICY_ERROR);
223 return;
224 }
225
226 NOTREACHED();
227 SetState(STATE_POLICY_ERROR);
228 }
229
230 void CloudPolicyController::OnDeviceTokenChanged() {
231 if (data_store_->device_token().empty()) {
232 // Additionally clear the generated device id to ensure we don't reuse old
233 // ids which could be potentially used for user tracking.
234 data_store_->set_device_id(std::string());
235 SetState(STATE_TOKEN_UNAVAILABLE);
236 } else {
237 SetState(STATE_TOKEN_VALID);
238 }
239 }
240
241 void CloudPolicyController::OnCredentialsChanged() {
242 // This notification is only interesting if we don't have a device token.
243 // If we already have a device token, that must be matching the current
244 // user, because (1) we always recreate the policy subsystem after user
245 // login (2) tokens are cached per user.
246 if (data_store_->device_token().empty()) {
247 notifier_->Inform(CloudPolicySubsystem::UNENROLLED,
248 CloudPolicySubsystem::NO_DETAILS,
249 PolicyNotifier::POLICY_CONTROLLER);
250 effective_policy_refresh_error_delay_ms_ =
251 kPolicyRefreshErrorDelayInMilliseconds;
252 SetState(STATE_TOKEN_UNAVAILABLE);
253 }
254 }
255
256 CloudPolicyController::CloudPolicyController(
257 DeviceManagementService* service,
258 CloudPolicyCacheBase* cache,
259 DeviceTokenFetcher* token_fetcher,
260 CloudPolicyDataStore* data_store,
261 PolicyNotifier* notifier,
262 DelayedWorkScheduler* scheduler) {
263 Initialize(service,
264 cache,
265 token_fetcher,
266 data_store,
267 notifier,
268 scheduler);
269 }
270
271 void CloudPolicyController::Initialize(
272 DeviceManagementService* service,
273 CloudPolicyCacheBase* cache,
274 DeviceTokenFetcher* token_fetcher,
275 CloudPolicyDataStore* data_store,
276 PolicyNotifier* notifier,
277 DelayedWorkScheduler* scheduler) {
278 DCHECK(cache);
279
280 service_ = service;
281 cache_ = cache;
282 token_fetcher_ = token_fetcher;
283 data_store_ = data_store;
284 notifier_ = notifier;
285 state_ = STATE_TOKEN_UNAVAILABLE;
286 policy_refresh_rate_ms_ = kPolicyRefreshRateInMilliseconds;
287 effective_policy_refresh_error_delay_ms_ =
288 kPolicyRefreshErrorDelayInMilliseconds;
289 scheduler_.reset(scheduler);
290 data_store_->AddObserver(this);
291 if (!data_store_->device_token().empty())
292 SetState(STATE_TOKEN_VALID);
293 else
294 SetState(STATE_TOKEN_UNAVAILABLE);
295 }
296
297 bool CloudPolicyController::ReadyToFetchToken() {
298 return data_store_->token_cache_loaded() &&
299 !data_store_->user_name().empty() &&
300 data_store_->has_auth_token();
301 }
302
303 void CloudPolicyController::FetchToken() {
304 if (ReadyToFetchToken()) {
305 if (BrowserPolicyConnector::IsNonEnterpriseUser(data_store_->user_name())) {
306 SetState(STATE_TOKEN_UNMANAGED);
307 } else {
308 // Either use an already prepopulated id or generate a new random device
309 // id. (It'll only be kept if registration succeeds.)
310 if (data_store_->device_id().empty())
311 data_store_->set_device_id(base::GenerateGUID());
312 token_fetcher_->FetchToken();
313 }
314 } else {
315 VLOG(1) << "Not ready to fetch DMToken yet, will try again later.";
316 }
317 }
318
319 void CloudPolicyController::SendPolicyRequest() {
320 DCHECK(!data_store_->device_token().empty());
321
322 if (!data_store_->policy_fetching_enabled())
323 return;
324
325 request_job_.reset(
326 service_->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH));
327 request_job_->SetDMToken(data_store_->device_token());
328 request_job_->SetClientID(data_store_->device_id());
329 request_job_->SetUserAffiliation(data_store_->user_affiliation());
330
331 em::DeviceManagementRequest* request = request_job_->GetRequest();
332 em::PolicyFetchRequest* fetch_request =
333 request->mutable_policy_request()->add_request();
334 fetch_request->set_signature_type(em::PolicyFetchRequest::SHA1_RSA);
335 fetch_request->set_policy_type(data_store_->policy_type());
336 if (cache_->machine_id_missing() && !data_store_->machine_id().empty())
337 fetch_request->set_machine_id(data_store_->machine_id());
338 if (!cache_->is_unmanaged() &&
339 !cache_->last_policy_refresh_time().is_null()) {
340 base::TimeDelta timestamp =
341 cache_->last_policy_refresh_time() - base::Time::UnixEpoch();
342 fetch_request->set_timestamp(timestamp.InMilliseconds());
343 }
344 int key_version = 0;
345 if (cache_->GetPublicKeyVersion(&key_version))
346 fetch_request->set_public_key_version(key_version);
347
348 #if defined(OS_CHROMEOS)
349 if (data_store_->device_status_collector()) {
350 data_store_->device_status_collector()->GetStatus(
351 request->mutable_device_status_report_request());
352 }
353 #endif
354
355 request_job_->Start(base::Bind(&CloudPolicyController::OnPolicyFetchCompleted,
356 base::Unretained(this)));
357 UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchRequested,
358 kMetricPolicySize);
359 }
360
361 void CloudPolicyController::DoWork() {
362 switch (state_) {
363 case STATE_TOKEN_UNAVAILABLE:
364 case STATE_TOKEN_ERROR:
365 FetchToken();
366 return;
367 case STATE_TOKEN_VALID:
368 case STATE_POLICY_VALID:
369 case STATE_POLICY_ERROR:
370 case STATE_POLICY_UNAVAILABLE:
371 SendPolicyRequest();
372 return;
373 case STATE_TOKEN_UNMANAGED:
374 return;
375 }
376
377 NOTREACHED() << "Unhandled state" << state_;
378 }
379
380 void CloudPolicyController::SetState(
381 CloudPolicyController::ControllerState new_state) {
382 state_ = new_state;
383
384 request_job_.reset(); // Stop any pending requests.
385
386 base::Time now(base::Time::NowFromSystemTime());
387 base::Time last_refresh(GetLastRefreshTime(now));
388 base::Time refresh_at;
389
390 // Determine when to take the next step.
391 bool inform_notifier_done = false;
392 switch (state_) {
393 case STATE_TOKEN_UNMANAGED:
394 notifier_->Inform(CloudPolicySubsystem::UNMANAGED,
395 CloudPolicySubsystem::NO_DETAILS,
396 PolicyNotifier::POLICY_CONTROLLER);
397 break;
398 case STATE_TOKEN_UNAVAILABLE:
399 // The controller is not yet initialized and needs to immediately fetch
400 // token and policy if present.
401 case STATE_TOKEN_VALID:
402 // Immediately try to fetch the token on initialization or policy after a
403 // token update. Subsequent retries will respect the back-off strategy.
404 refresh_at = now;
405 // |notifier_| isn't informed about anything at this point, we wait for
406 // the result of the next action first.
407 break;
408 case STATE_POLICY_VALID:
409 // Delay is only reset if the policy fetch operation was successful. This
410 // will ensure the server won't get overloaded with retries in case of
411 // a bug on either side.
412 effective_policy_refresh_error_delay_ms_ =
413 kPolicyRefreshErrorDelayInMilliseconds;
414 refresh_at = last_refresh + GetRefreshDelay();
415 notifier_->Inform(CloudPolicySubsystem::SUCCESS,
416 CloudPolicySubsystem::NO_DETAILS,
417 PolicyNotifier::POLICY_CONTROLLER);
418 break;
419 case STATE_TOKEN_ERROR:
420 notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
421 CloudPolicySubsystem::BAD_DMTOKEN,
422 PolicyNotifier::POLICY_CONTROLLER);
423 inform_notifier_done = true;
424 case STATE_POLICY_ERROR:
425 if (!inform_notifier_done) {
426 notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
427 CloudPolicySubsystem::POLICY_NETWORK_ERROR,
428 PolicyNotifier::POLICY_CONTROLLER);
429 }
430 refresh_at = now + base::TimeDelta::FromMilliseconds(
431 effective_policy_refresh_error_delay_ms_);
432 effective_policy_refresh_error_delay_ms_ =
433 std::min(effective_policy_refresh_error_delay_ms_ * 2,
434 policy_refresh_rate_ms_);
435 break;
436 case STATE_POLICY_UNAVAILABLE:
437 effective_policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_;
438 refresh_at = now + base::TimeDelta::FromMilliseconds(
439 effective_policy_refresh_error_delay_ms_);
440 notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
441 CloudPolicySubsystem::POLICY_NETWORK_ERROR,
442 PolicyNotifier::POLICY_CONTROLLER);
443 break;
444 }
445
446 // Update the delayed work task.
447 scheduler_->CancelDelayedWork();
448 if (!refresh_at.is_null())
449 ScheduleDelayedWorkTask(refresh_at - now);
450
451 // Inform the cache if a fetch attempt has completed. This happens if policy
452 // has been succesfully fetched, or if token or policy fetching failed.
453 if (state_ != STATE_TOKEN_UNAVAILABLE && state_ != STATE_TOKEN_VALID)
454 cache_->SetFetchingDone();
455 }
456
457 base::TimeDelta CloudPolicyController::GetRefreshDelay() {
458 int64 deviation = (kPolicyRefreshDeviationFactorPercent *
459 policy_refresh_rate_ms_) / 100;
460 deviation = std::min(deviation, kPolicyRefreshDeviationMaxInMilliseconds);
461 return base::TimeDelta::FromMilliseconds(
462 policy_refresh_rate_ms_ - base::RandGenerator(deviation + 1));
463 }
464
465 void CloudPolicyController::ScheduleDelayedWorkTask(
466 const base::TimeDelta& delay) {
467 int64 effective_delay = std::max<int64>(delay.InMilliseconds(), 0);
468 scheduler_->PostDelayedWork(
469 base::Bind(&CloudPolicyController::DoWork, base::Unretained(this)),
470 effective_delay);
471 }
472
473 base::Time CloudPolicyController::GetLastRefreshTime(const base::Time& now) {
474 base::Time last_refresh(cache_->last_policy_refresh_time());
475 if (last_refresh.is_null())
476 last_refresh = now;
477
478 return last_refresh;
479 }
480
481 } // namespace policy
OLDNEW
« no previous file with comments | « chrome/browser/policy/cloud_policy_controller.h ('k') | chrome/browser/policy/cloud_policy_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698