• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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