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/device_token_fetcher.h"
6
7 #include <algorithm>
8
9 #include "base/message_loop.h"
10 #include "chrome/browser/policy/cloud_policy_cache_base.h"
11 #include "chrome/browser/policy/device_management_service.h"
12 #include "chrome/browser/policy/proto/device_management_constants.h"
13 #include "chrome/browser/policy/proto/device_management_local.pb.h"
14
15 namespace {
16
17 // Retry after 5 minutes (with exponential backoff) after token fetch errors.
18 const int64 kTokenFetchErrorDelayMilliseconds = 5 * 60 * 1000;
19 // Retry after max 3 hours after token fetch errors.
20 const int64 kTokenFetchErrorMaxDelayMilliseconds = 3 * 60 * 60 * 1000;
21 // For unmanaged devices, check once per day whether they're still unmanaged.
22 const int64 kUnmanagedDeviceRefreshRateMilliseconds = 24 * 60 * 60 * 1000;
23
24 } // namespace
25
26 namespace policy {
27
28 namespace em = enterprise_management;
29
DeviceTokenFetcher(DeviceManagementService * service,CloudPolicyCacheBase * cache,PolicyNotifier * notifier)30 DeviceTokenFetcher::DeviceTokenFetcher(
31 DeviceManagementService* service,
32 CloudPolicyCacheBase* cache,
33 PolicyNotifier* notifier)
34 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
35 Initialize(service,
36 cache,
37 notifier,
38 kTokenFetchErrorDelayMilliseconds,
39 kTokenFetchErrorMaxDelayMilliseconds,
40 kUnmanagedDeviceRefreshRateMilliseconds);
41 }
42
DeviceTokenFetcher(DeviceManagementService * service,CloudPolicyCacheBase * cache,PolicyNotifier * notifier,int64 token_fetch_error_delay_ms,int64 token_fetch_error_max_delay_ms,int64 unmanaged_device_refresh_rate_ms)43 DeviceTokenFetcher::DeviceTokenFetcher(
44 DeviceManagementService* service,
45 CloudPolicyCacheBase* cache,
46 PolicyNotifier* notifier,
47 int64 token_fetch_error_delay_ms,
48 int64 token_fetch_error_max_delay_ms,
49 int64 unmanaged_device_refresh_rate_ms)
50 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
51 Initialize(service,
52 cache,
53 notifier,
54 token_fetch_error_delay_ms,
55 token_fetch_error_max_delay_ms,
56 unmanaged_device_refresh_rate_ms);
57 }
58
~DeviceTokenFetcher()59 DeviceTokenFetcher::~DeviceTokenFetcher() {
60 CancelRetryTask();
61 }
62
FetchToken(const std::string & auth_token,const std::string & device_id,em::DeviceRegisterRequest_Type policy_type,const std::string & machine_id,const std::string & machine_model)63 void DeviceTokenFetcher::FetchToken(
64 const std::string& auth_token,
65 const std::string& device_id,
66 em::DeviceRegisterRequest_Type policy_type,
67 const std::string& machine_id,
68 const std::string& machine_model) {
69 SetState(STATE_INACTIVE);
70 auth_token_ = auth_token;
71 device_id_ = device_id;
72 policy_type_ = policy_type;
73 machine_id_ = machine_id;
74 machine_model_ = machine_model;
75 FetchTokenInternal();
76 }
77
FetchTokenInternal()78 void DeviceTokenFetcher::FetchTokenInternal() {
79 DCHECK(state_ != STATE_TOKEN_AVAILABLE);
80 if (auth_token_.empty() || device_id_.empty()) {
81 // Maybe this device is unmanaged, just exit. The CloudPolicyController
82 // will call FetchToken() again if something changes.
83 return;
84 }
85 // Construct a new backend, which will discard any previous requests.
86 backend_.reset(service_->CreateBackend());
87 em::DeviceRegisterRequest request;
88 request.set_type(policy_type_);
89 if (!machine_id_.empty())
90 request.set_machine_id(machine_id_);
91 if (!machine_model_.empty())
92 request.set_machine_model(machine_model_);
93 backend_->ProcessRegisterRequest(auth_token_, device_id_, request, this);
94 }
95
SetUnmanagedState()96 void DeviceTokenFetcher::SetUnmanagedState() {
97 // The call to |cache_->SetUnmanaged()| has to happen first because it sets
98 // the timestamp that |SetState()| needs to determine the correct refresh
99 // time.
100 cache_->SetUnmanaged();
101 SetState(STATE_UNMANAGED);
102 }
103
GetDeviceToken()104 const std::string& DeviceTokenFetcher::GetDeviceToken() {
105 return device_token_;
106 }
107
StopAutoRetry()108 void DeviceTokenFetcher::StopAutoRetry() {
109 CancelRetryTask();
110 backend_.reset();
111 device_token_.clear();
112 auth_token_.clear();
113 device_id_.clear();
114 }
115
AddObserver(DeviceTokenFetcher::Observer * observer)116 void DeviceTokenFetcher::AddObserver(DeviceTokenFetcher::Observer* observer) {
117 observer_list_.AddObserver(observer);
118 }
119
RemoveObserver(DeviceTokenFetcher::Observer * observer)120 void DeviceTokenFetcher::RemoveObserver(
121 DeviceTokenFetcher::Observer* observer) {
122 observer_list_.RemoveObserver(observer);
123 }
124
HandleRegisterResponse(const em::DeviceRegisterResponse & response)125 void DeviceTokenFetcher::HandleRegisterResponse(
126 const em::DeviceRegisterResponse& response) {
127 if (response.has_device_management_token()) {
128 device_token_ = response.device_management_token();
129 SetState(STATE_TOKEN_AVAILABLE);
130 } else {
131 NOTREACHED();
132 SetState(STATE_ERROR);
133 }
134 }
135
OnError(DeviceManagementBackend::ErrorCode code)136 void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) {
137 switch (code) {
138 case DeviceManagementBackend::kErrorServiceManagementNotSupported:
139 cache_->SetUnmanaged();
140 SetState(STATE_UNMANAGED);
141 break;
142 case DeviceManagementBackend::kErrorRequestFailed:
143 case DeviceManagementBackend::kErrorTemporaryUnavailable:
144 case DeviceManagementBackend::kErrorServiceDeviceNotFound:
145 SetState(STATE_TEMPORARY_ERROR);
146 break;
147 case DeviceManagementBackend::kErrorServiceManagementTokenInvalid:
148 // Most probably the GAIA auth cookie has expired. We can not do anything
149 // until the user logs-in again.
150 SetState(STATE_BAD_AUTH);
151 break;
152 default:
153 SetState(STATE_ERROR);
154 }
155 }
156
Initialize(DeviceManagementService * service,CloudPolicyCacheBase * cache,PolicyNotifier * notifier,int64 token_fetch_error_delay_ms,int64 token_fetch_error_max_delay_ms,int64 unmanaged_device_refresh_rate_ms)157 void DeviceTokenFetcher::Initialize(DeviceManagementService* service,
158 CloudPolicyCacheBase* cache,
159 PolicyNotifier* notifier,
160 int64 token_fetch_error_delay_ms,
161 int64 token_fetch_error_max_delay_ms,
162 int64 unmanaged_device_refresh_rate_ms) {
163 service_ = service;
164 cache_ = cache;
165 notifier_ = notifier;
166 token_fetch_error_delay_ms_ = token_fetch_error_delay_ms;
167 token_fetch_error_max_delay_ms_ = token_fetch_error_max_delay_ms;
168 effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms;
169 unmanaged_device_refresh_rate_ms_ = unmanaged_device_refresh_rate_ms;
170 state_ = STATE_INACTIVE;
171 retry_task_ = NULL;
172
173 if (cache_->is_unmanaged())
174 SetState(STATE_UNMANAGED);
175 }
176
SetState(FetcherState state)177 void DeviceTokenFetcher::SetState(FetcherState state) {
178 state_ = state;
179 if (state_ != STATE_ERROR)
180 effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms_;
181
182 base::Time delayed_work_at;
183 switch (state_) {
184 case STATE_INACTIVE:
185 device_token_.clear();
186 auth_token_.clear();
187 device_id_.clear();
188 notifier_->Inform(CloudPolicySubsystem::UNENROLLED,
189 CloudPolicySubsystem::NO_DETAILS,
190 PolicyNotifier::TOKEN_FETCHER);
191 break;
192 case STATE_TOKEN_AVAILABLE:
193 FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceTokenAvailable());
194 notifier_->Inform(CloudPolicySubsystem::SUCCESS,
195 CloudPolicySubsystem::NO_DETAILS,
196 PolicyNotifier::TOKEN_FETCHER);
197 break;
198 case STATE_UNMANAGED:
199 delayed_work_at = cache_->last_policy_refresh_time() +
200 base::TimeDelta::FromMilliseconds(unmanaged_device_refresh_rate_ms_);
201 notifier_->Inform(CloudPolicySubsystem::UNMANAGED,
202 CloudPolicySubsystem::NO_DETAILS,
203 PolicyNotifier::TOKEN_FETCHER);
204 break;
205 case STATE_TEMPORARY_ERROR:
206 delayed_work_at = base::Time::Now() +
207 base::TimeDelta::FromMilliseconds(
208 effective_token_fetch_error_delay_ms_);
209 effective_token_fetch_error_delay_ms_ =
210 std::min(effective_token_fetch_error_delay_ms_ * 2,
211 token_fetch_error_max_delay_ms_);
212 notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
213 CloudPolicySubsystem::DMTOKEN_NETWORK_ERROR,
214 PolicyNotifier::TOKEN_FETCHER);
215 break;
216 case STATE_ERROR:
217 effective_token_fetch_error_delay_ms_ = token_fetch_error_max_delay_ms_;
218 delayed_work_at = base::Time::Now() +
219 base::TimeDelta::FromMilliseconds(
220 effective_token_fetch_error_delay_ms_);
221 notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
222 CloudPolicySubsystem::DMTOKEN_NETWORK_ERROR,
223 PolicyNotifier::TOKEN_FETCHER);
224 break;
225 case STATE_BAD_AUTH:
226 // Can't do anything, need to wait for new credentials.
227 notifier_->Inform(CloudPolicySubsystem::BAD_GAIA_TOKEN,
228 CloudPolicySubsystem::NO_DETAILS,
229 PolicyNotifier::TOKEN_FETCHER);
230 break;
231 }
232
233 CancelRetryTask();
234 if (!delayed_work_at.is_null()) {
235 base::Time now(base::Time::Now());
236 int64 delay = std::max<int64>((delayed_work_at - now).InMilliseconds(), 0);
237 retry_task_ = method_factory_.NewRunnableMethod(
238 &DeviceTokenFetcher::ExecuteRetryTask);
239 MessageLoop::current()->PostDelayedTask(FROM_HERE, retry_task_,
240 delay);
241 }
242 }
243
ExecuteRetryTask()244 void DeviceTokenFetcher::ExecuteRetryTask() {
245 DCHECK(retry_task_);
246 retry_task_ = NULL;
247
248 switch (state_) {
249 case STATE_INACTIVE:
250 case STATE_TOKEN_AVAILABLE:
251 break;
252 case STATE_UNMANAGED:
253 case STATE_ERROR:
254 case STATE_TEMPORARY_ERROR:
255 case STATE_BAD_AUTH:
256 FetchTokenInternal();
257 break;
258 }
259 }
260
CancelRetryTask()261 void DeviceTokenFetcher::CancelRetryTask() {
262 if (retry_task_) {
263 retry_task_->Cancel();
264 retry_task_ = NULL;
265 }
266 }
267
268 } // namespace policy
269