1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Use of this source code is governed by a BSD-style license that can be
3dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// found in the LICENSE file.
4dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
5dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/policy/cloud_policy_controller.h"
6dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
7dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <algorithm>
8dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/logging.h"
10dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/message_loop.h"
11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/rand_util.h"
12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/string_util.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/policy/cloud_policy_cache_base.h"
14dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/policy/cloud_policy_subsystem.h"
15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/policy/device_management_backend.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/policy/device_management_service.h"
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/policy/proto/device_management_constants.h"
18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Domain names that are known not to be managed.
20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// We don't register the device when such a user logs in.
21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstatic const char* kNonManagedDomains[] = {
22dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  "@googlemail.com",
23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  "@gmail.com"
24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen};
25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Checks the domain part of the given username against the list of known
27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// non-managed domain names. Returns false if |username| is empty or
28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// in a domain known not to be managed.
29dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstatic bool CanBeInManagedDomain(const std::string& username) {
30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (username.empty()) {
31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // This means incognito user in case of ChromiumOS and
32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // no logged-in user in case of Chromium (SigninService).
33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
35dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  for (size_t i = 0; i < arraysize(kNonManagedDomains); i++) {
36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (EndsWith(username, kNonManagedDomains[i], true)) {
37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return false;
38dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
39dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
40dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return true;
41dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
42dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
43dc0f95d653279beabeb9817299e2902918ba123eKristian Monsennamespace policy {
44dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
45dc0f95d653279beabeb9817299e2902918ba123eKristian Monsennamespace em = enterprise_management;
46dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
47dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// The maximum ratio in percent of the policy refresh rate we use for adjusting
48dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// the policy refresh time instant. The rationale is to avoid load spikes from
49dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// many devices that were set up in sync for some reason.
50dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstatic const int kPolicyRefreshDeviationFactorPercent = 10;
51dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Maximum deviation we are willing to accept.
52dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstatic const int64 kPolicyRefreshDeviationMaxInMilliseconds = 30 * 60 * 1000;
53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
54dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// These are the base values for delays before retrying after an error. They
55dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// will be doubled each time they are used.
56dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstatic const int64 kPolicyRefreshErrorDelayInMilliseconds =
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    5 * 60 * 1000;  // 5 minutes
58dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
59dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Default value for the policy refresh rate.
60dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstatic const int kPolicyRefreshRateInMilliseconds =
61dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    3 * 60 * 60 * 1000;  // 3 hours.
62dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
63dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenCloudPolicyController::CloudPolicyController(
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DeviceManagementService* service,
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CloudPolicyCacheBase* cache,
66dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    DeviceTokenFetcher* token_fetcher,
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CloudPolicyIdentityStrategy* identity_strategy,
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PolicyNotifier* notifier)
69dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Initialize(service,
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen             cache,
72dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             token_fetcher,
73dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             identity_strategy,
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen             notifier,
75dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             kPolicyRefreshRateInMilliseconds,
76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             kPolicyRefreshDeviationFactorPercent,
77dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             kPolicyRefreshDeviationMaxInMilliseconds,
78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             kPolicyRefreshErrorDelayInMilliseconds);
79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
80dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
81dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenCloudPolicyController::~CloudPolicyController() {
82dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  token_fetcher_->RemoveObserver(this);
83dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  identity_strategy_->RemoveObserver(this);
84dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  CancelDelayedWork();
85dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
86dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
87dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::SetRefreshRate(int64 refresh_rate_milliseconds) {
88dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  policy_refresh_rate_ms_ = refresh_rate_milliseconds;
89dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
90dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Reschedule the refresh task if necessary.
91dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (state_ == STATE_POLICY_VALID)
92dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SetState(STATE_POLICY_VALID);
93dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid CloudPolicyController::Retry() {
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CancelDelayedWork();
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DoWork();
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid CloudPolicyController::StopAutoRetry() {
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CancelDelayedWork();
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  backend_.reset();
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
105dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::HandlePolicyResponse(
106dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const em::DevicePolicyResponse& response) {
107dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (response.response_size() > 0) {
108dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (response.response_size() > 1) {
109dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      LOG(WARNING) << "More than one policy in the response of the device "
110dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                   << "management server, discarding.";
111dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (response.response(0).error_code() !=
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        DeviceManagementBackend::kErrorServicePolicyNotFound) {
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      cache_->SetPolicy(response.response(0));
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SetState(STATE_POLICY_VALID);
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SetState(STATE_POLICY_UNAVAILABLE);
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
122dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::OnError(DeviceManagementBackend::ErrorCode code) {
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  switch (code) {
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DeviceManagementBackend::kErrorServiceDeviceNotFound:
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DeviceManagementBackend::kErrorServiceManagementTokenInvalid: {
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LOG(WARNING) << "The device token was either invalid or unknown to the "
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                   << "device manager, re-registering device.";
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Will retry fetching a token but gracefully backing off.
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SetState(STATE_TOKEN_ERROR);
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DeviceManagementBackend::kErrorServiceManagementNotSupported: {
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      VLOG(1) << "The device is no longer managed.";
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      token_fetcher_->SetUnmanagedState();
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SetState(STATE_TOKEN_UNMANAGED);
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DeviceManagementBackend::kErrorServicePolicyNotFound:
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DeviceManagementBackend::kErrorRequestInvalid:
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DeviceManagementBackend::kErrorServiceActivationPending:
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DeviceManagementBackend::kErrorResponseDecoding:
142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DeviceManagementBackend::kErrorHttpStatus: {
143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      VLOG(1) << "An error in the communication with the policy server occurred"
144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              << ", will retry in a few hours.";
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SetState(STATE_POLICY_UNAVAILABLE);
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DeviceManagementBackend::kErrorRequestFailed:
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DeviceManagementBackend::kErrorTemporaryUnavailable: {
150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      VLOG(1) << "A temporary error in the communication with the policy server"
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              << " occurred.";
152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Will retry last operation but gracefully backing off.
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SetState(STATE_POLICY_ERROR);
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
155dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
156dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
158dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::OnDeviceTokenAvailable() {
159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  identity_strategy_->OnDeviceTokenAvailable(token_fetcher_->GetDeviceToken());
160dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
162dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::OnDeviceTokenChanged() {
163dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (identity_strategy_->GetDeviceToken().empty())
164dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SetState(STATE_TOKEN_UNAVAILABLE);
165dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  else
166dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SetState(STATE_TOKEN_VALID);
167dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
168dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
169dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::OnCredentialsChanged() {
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms_;
171dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SetState(STATE_TOKEN_UNAVAILABLE);
172dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
173dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
174dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenCloudPolicyController::CloudPolicyController(
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DeviceManagementService* service,
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CloudPolicyCacheBase* cache,
177dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    DeviceTokenFetcher* token_fetcher,
178dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    CloudPolicyIdentityStrategy* identity_strategy,
179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PolicyNotifier* notifier,
180dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int64 policy_refresh_rate_ms,
181dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int policy_refresh_deviation_factor_percent,
182dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int64 policy_refresh_deviation_max_ms,
183dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int64 policy_refresh_error_delay_ms)
184dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Initialize(service,
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen             cache,
187dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             token_fetcher,
188dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             identity_strategy,
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen             notifier,
190dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             policy_refresh_rate_ms,
191dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             policy_refresh_deviation_factor_percent,
192dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             policy_refresh_deviation_max_ms,
193dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen             policy_refresh_error_delay_ms);
194dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
195dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
196dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::Initialize(
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DeviceManagementService* service,
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CloudPolicyCacheBase* cache,
199dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    DeviceTokenFetcher* token_fetcher,
200dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    CloudPolicyIdentityStrategy* identity_strategy,
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PolicyNotifier* notifier,
202dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int64 policy_refresh_rate_ms,
203dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int policy_refresh_deviation_factor_percent,
204dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int64 policy_refresh_deviation_max_ms,
205dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int64 policy_refresh_error_delay_ms) {
206dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(cache);
207dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  service_ = service;
209dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  cache_ = cache;
210dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  token_fetcher_ = token_fetcher;
211dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  identity_strategy_ = identity_strategy;
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  notifier_ = notifier;
213dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  state_ = STATE_TOKEN_UNAVAILABLE;
214dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  delayed_work_task_ = NULL;
215dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  policy_refresh_rate_ms_ = policy_refresh_rate_ms;
216dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  policy_refresh_deviation_factor_percent_ =
217dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      policy_refresh_deviation_factor_percent;
218dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  policy_refresh_deviation_max_ms_ = policy_refresh_deviation_max_ms;
219dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms;
220dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms;
221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
222dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  token_fetcher_->AddObserver(this);
223dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  identity_strategy_->AddObserver(this);
224dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!identity_strategy_->GetDeviceToken().empty())
225dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SetState(STATE_TOKEN_VALID);
226dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  else
227dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SetState(STATE_TOKEN_UNAVAILABLE);
228dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
229dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
230dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::FetchToken() {
231dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string username;
232dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string auth_token;
233dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string device_id = identity_strategy_->GetDeviceID();
234dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string machine_id = identity_strategy_->GetMachineID();
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string machine_model = identity_strategy_->GetMachineModel();
236dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  em::DeviceRegisterRequest_Type policy_type =
237dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      identity_strategy_->GetPolicyRegisterType();
238dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (identity_strategy_->GetCredentials(&username, &auth_token) &&
239dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      CanBeInManagedDomain(username)) {
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    token_fetcher_->FetchToken(auth_token, device_id, policy_type,
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                               machine_id, machine_model);
242dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
243dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
244dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
245dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::SendPolicyRequest() {
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  backend_.reset(service_->CreateBackend());
247dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!identity_strategy_->GetDeviceToken().empty());
248dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  em::DevicePolicyRequest policy_request;
249dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  em::PolicyFetchRequest* fetch_request = policy_request.add_request();
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  fetch_request->set_signature_type(em::PolicyFetchRequest::SHA1_RSA);
251dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  fetch_request->set_policy_type(identity_strategy_->GetPolicyType());
252dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!cache_->is_unmanaged() &&
253dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      !cache_->last_policy_refresh_time().is_null()) {
254dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    base::TimeDelta timestamp =
255dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        cache_->last_policy_refresh_time() - base::Time::UnixEpoch();
256dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    fetch_request->set_timestamp(timestamp.InMilliseconds());
257dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int key_version = 0;
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (cache_->GetPublicKeyVersion(&key_version))
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    fetch_request->set_public_key_version(key_version);
261dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
262dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  backend_->ProcessPolicyRequest(identity_strategy_->GetDeviceToken(),
263dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                 identity_strategy_->GetDeviceID(),
264dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                 policy_request, this);
265dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
266dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
267dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::DoDelayedWork() {
268dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(delayed_work_task_);
269dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  delayed_work_task_ = NULL;
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DoWork();
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
272dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid CloudPolicyController::DoWork() {
274dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  switch (state_) {
275dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case STATE_TOKEN_UNAVAILABLE:
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case STATE_TOKEN_ERROR:
277dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      FetchToken();
278dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
279dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case STATE_TOKEN_VALID:
280dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case STATE_POLICY_VALID:
281dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case STATE_POLICY_ERROR:
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case STATE_POLICY_UNAVAILABLE:
283dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      SendPolicyRequest();
284dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case STATE_TOKEN_UNMANAGED:
286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
287dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
288dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
289dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  NOTREACHED() << "Unhandled state" << state_;
290dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
291dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
292dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::CancelDelayedWork() {
293dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (delayed_work_task_) {
294dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delayed_work_task_->Cancel();
295dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delayed_work_task_ = NULL;
296dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
297dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
298dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
299dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid CloudPolicyController::SetState(
300dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    CloudPolicyController::ControllerState new_state) {
301dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  state_ = new_state;
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  backend_.reset();  // Discard any pending requests.
303dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
304dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  base::Time now(base::Time::NowFromSystemTime());
305dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  base::Time refresh_at;
306dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  base::Time last_refresh(cache_->last_policy_refresh_time());
307dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (last_refresh.is_null())
308dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    last_refresh = now;
309dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
310dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Determine when to take the next step.
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool inform_notifier_done = false;
312dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  switch (state_) {
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case STATE_TOKEN_UNMANAGED:
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      notifier_->Inform(CloudPolicySubsystem::UNMANAGED,
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        CloudPolicySubsystem::NO_DETAILS,
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        PolicyNotifier::POLICY_CONTROLLER);
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
318dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case STATE_TOKEN_UNAVAILABLE:
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // The controller is not yet initialized and needs to immediately fetch
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // token and policy if present.
321dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case STATE_TOKEN_VALID:
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Immediately try to fetch the token on initialization or policy after a
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // token update. Subsequent retries will respect the back-off strategy.
324dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      refresh_at = now;
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // |notifier_| isn't informed about anything at this point, we wait for
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // the result of the next action first.
327dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      break;
328dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case STATE_POLICY_VALID:
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Delay is only reset if the policy fetch operation was successful. This
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // will ensure the server won't get overloaded with retries in case of
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // a bug on either side.
332dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms_;
333dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      refresh_at =
334dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          last_refresh + base::TimeDelta::FromMilliseconds(GetRefreshDelay());
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      notifier_->Inform(CloudPolicySubsystem::SUCCESS,
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        CloudPolicySubsystem::NO_DETAILS,
337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        PolicyNotifier::POLICY_CONTROLLER);
338dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      break;
339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case STATE_TOKEN_ERROR:
340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        CloudPolicySubsystem::BAD_DMTOKEN,
342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        PolicyNotifier::POLICY_CONTROLLER);
343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      inform_notifier_done = true;
344dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case STATE_POLICY_ERROR:
345ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!inform_notifier_done) {
346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          CloudPolicySubsystem::POLICY_NETWORK_ERROR,
348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          PolicyNotifier::POLICY_CONTROLLER);
349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      refresh_at = now + base::TimeDelta::FromMilliseconds(
351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             effective_policy_refresh_error_delay_ms_);
352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      effective_policy_refresh_error_delay_ms_ =
353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          std::min(effective_policy_refresh_error_delay_ms_ * 2,
354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                   policy_refresh_rate_ms_);
355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case STATE_POLICY_UNAVAILABLE:
357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      effective_policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_;
358dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      refresh_at = now + base::TimeDelta::FromMilliseconds(
359dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                             effective_policy_refresh_error_delay_ms_);
360ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        CloudPolicySubsystem::POLICY_NETWORK_ERROR,
362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        PolicyNotifier::POLICY_CONTROLLER);
363dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      break;
364dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
365dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
366dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Update the delayed work task.
367dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  CancelDelayedWork();
368dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!refresh_at.is_null()) {
369dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int64 delay = std::max<int64>((refresh_at - now).InMilliseconds(), 0);
370dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delayed_work_task_ = method_factory_.NewRunnableMethod(
371dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        &CloudPolicyController::DoDelayedWork);
372dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_work_task_,
373dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                            delay);
374dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
375dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
376dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
377dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenint64 CloudPolicyController::GetRefreshDelay() {
378dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  int64 deviation = (policy_refresh_deviation_factor_percent_ *
379dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                     policy_refresh_rate_ms_) / 100;
380dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  deviation = std::min(deviation, policy_refresh_deviation_max_ms_);
381dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return policy_refresh_rate_ms_ - base::RandGenerator(deviation + 1);
382dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
383dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
384dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}  // namespace policy
385