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 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 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 59 DeviceTokenFetcher::~DeviceTokenFetcher() { 60 CancelRetryTask(); 61 } 62 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 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 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 104 const std::string& DeviceTokenFetcher::GetDeviceToken() { 105 return device_token_; 106 } 107 108 void DeviceTokenFetcher::StopAutoRetry() { 109 CancelRetryTask(); 110 backend_.reset(); 111 device_token_.clear(); 112 auth_token_.clear(); 113 device_id_.clear(); 114 } 115 116 void DeviceTokenFetcher::AddObserver(DeviceTokenFetcher::Observer* observer) { 117 observer_list_.AddObserver(observer); 118 } 119 120 void DeviceTokenFetcher::RemoveObserver( 121 DeviceTokenFetcher::Observer* observer) { 122 observer_list_.RemoveObserver(observer); 123 } 124 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 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 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 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 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 261 void DeviceTokenFetcher::CancelRetryTask() { 262 if (retry_task_) { 263 retry_task_->Cancel(); 264 retry_task_ = NULL; 265 } 266 } 267 268 } // namespace policy 269