Home | History | Annotate | Download | only in policy
      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