| Index: chrome/browser/policy/cloud_policy_controller.cc
|
| diff --git a/chrome/browser/policy/cloud_policy_controller.cc b/chrome/browser/policy/cloud_policy_controller.cc
|
| deleted file mode 100644
|
| index bd4b9b56d8095c935152072364fd163b60f6e603..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/policy/cloud_policy_controller.cc
|
| +++ /dev/null
|
| @@ -1,481 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/policy/cloud_policy_controller.h"
|
| -
|
| -#include <algorithm>
|
| -#include <string>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/guid.h"
|
| -#include "base/logging.h"
|
| -#include "base/metrics/histogram.h"
|
| -#include "base/rand_util.h"
|
| -#include "chrome/browser/policy/browser_policy_connector.h"
|
| -#include "chrome/browser/policy/cloud_policy_cache_base.h"
|
| -#include "chrome/browser/policy/cloud_policy_constants.h"
|
| -#include "chrome/browser/policy/cloud_policy_subsystem.h"
|
| -#include "chrome/browser/policy/delayed_work_scheduler.h"
|
| -#include "chrome/browser/policy/device_management_service.h"
|
| -#include "chrome/browser/policy/device_token_fetcher.h"
|
| -#include "chrome/browser/policy/enterprise_metrics.h"
|
| -#include "chrome/browser/policy/policy_notifier.h"
|
| -
|
| -namespace policy {
|
| -
|
| -namespace {
|
| -
|
| -// The maximum ratio in percent of the policy refresh rate we use for adjusting
|
| -// the policy refresh time instant. The rationale is to avoid load spikes from
|
| -// many devices that were set up in sync for some reason.
|
| -const int kPolicyRefreshDeviationFactorPercent = 10;
|
| -// Maximum deviation we are willing to accept.
|
| -const int64 kPolicyRefreshDeviationMaxInMilliseconds = 30 * 60 * 1000;
|
| -
|
| -// These are the base values for delays before retrying after an error. They
|
| -// will be doubled each time they are used.
|
| -const int64 kPolicyRefreshErrorDelayInMilliseconds =
|
| - 5 * 60 * 1000; // 5 minutes.
|
| -
|
| -// Default value for the policy refresh rate.
|
| -const int kPolicyRefreshRateInMilliseconds = 3 * 60 * 60 * 1000; // 3 hours.
|
| -
|
| -// Records the UMA metric corresponding to |status|, if it represents an error.
|
| -// Also records that a fetch response was received.
|
| -void SampleErrorStatus(DeviceManagementStatus status) {
|
| - UMA_HISTOGRAM_ENUMERATION(kMetricPolicy,
|
| - kMetricPolicyFetchResponseReceived,
|
| - kMetricPolicySize);
|
| - int sample = -1;
|
| - switch (status) {
|
| - case DM_STATUS_SUCCESS:
|
| - return;
|
| - case DM_STATUS_SERVICE_POLICY_NOT_FOUND:
|
| - sample = kMetricPolicyFetchNotFound;
|
| - break;
|
| - case DM_STATUS_SERVICE_DEVICE_NOT_FOUND:
|
| - sample = kMetricPolicyFetchInvalidToken;
|
| - break;
|
| - case DM_STATUS_RESPONSE_DECODING_ERROR:
|
| - sample = kMetricPolicyFetchBadResponse;
|
| - break;
|
| - case DM_STATUS_REQUEST_FAILED:
|
| - case DM_STATUS_REQUEST_INVALID:
|
| - case DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID:
|
| - sample = kMetricPolicyFetchRequestFailed;
|
| - break;
|
| - case DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED:
|
| - case DM_STATUS_SERVICE_DEVICE_ID_CONFLICT:
|
| - case DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER:
|
| - case DM_STATUS_TEMPORARY_UNAVAILABLE:
|
| - case DM_STATUS_SERVICE_ACTIVATION_PENDING:
|
| - case DM_STATUS_HTTP_STATUS_ERROR:
|
| - case DM_STATUS_SERVICE_MISSING_LICENSES:
|
| - sample = kMetricPolicyFetchServerFailed;
|
| - break;
|
| - }
|
| - if (sample != -1)
|
| - UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, sample, kMetricPolicySize);
|
| - else
|
| - NOTREACHED();
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace em = enterprise_management;
|
| -
|
| -CloudPolicyController::CloudPolicyController(
|
| - DeviceManagementService* service,
|
| - CloudPolicyCacheBase* cache,
|
| - DeviceTokenFetcher* token_fetcher,
|
| - CloudPolicyDataStore* data_store,
|
| - PolicyNotifier* notifier) {
|
| - Initialize(service,
|
| - cache,
|
| - token_fetcher,
|
| - data_store,
|
| - notifier,
|
| - new DelayedWorkScheduler);
|
| -}
|
| -
|
| -CloudPolicyController::~CloudPolicyController() {
|
| - data_store_->RemoveObserver(this);
|
| - scheduler_->CancelDelayedWork();
|
| -}
|
| -
|
| -void CloudPolicyController::SetRefreshRate(int64 refresh_rate_milliseconds) {
|
| - policy_refresh_rate_ms_ = refresh_rate_milliseconds;
|
| -
|
| - // Reschedule the refresh task if necessary.
|
| - if (state_ == STATE_POLICY_VALID) {
|
| - scheduler_->CancelDelayedWork();
|
| - base::Time now(base::Time::NowFromSystemTime());
|
| - ScheduleDelayedWorkTask(
|
| - (GetLastRefreshTime(now) + GetRefreshDelay()) - now);
|
| - }
|
| -}
|
| -
|
| -void CloudPolicyController::Retry() {
|
| - scheduler_->CancelDelayedWork();
|
| - DoWork();
|
| -}
|
| -
|
| -void CloudPolicyController::Reset() {
|
| - SetState(STATE_TOKEN_UNAVAILABLE);
|
| -}
|
| -
|
| -void CloudPolicyController::RefreshPolicies(bool wait_for_auth_token) {
|
| - // This call must eventually trigger a notification to the cache.
|
| - if (data_store_->device_token().empty()) {
|
| - // The DMToken has to be fetched.
|
| - if (ReadyToFetchToken()) {
|
| - SetState(STATE_TOKEN_UNAVAILABLE);
|
| - } else if (!wait_for_auth_token) {
|
| - // The controller doesn't have enough material to start a token fetch,
|
| - // but observers of the cache are waiting for the refresh.
|
| - SetState(STATE_TOKEN_UNMANAGED);
|
| - }
|
| - } else {
|
| - // The token is valid, so the next step is to fetch policy.
|
| - SetState(STATE_TOKEN_VALID);
|
| - }
|
| -}
|
| -
|
| -void CloudPolicyController::OnPolicyFetchCompleted(
|
| - DeviceManagementStatus status,
|
| - const em::DeviceManagementResponse& response) {
|
| - if (status == DM_STATUS_SUCCESS && !response.has_policy_response()) {
|
| - // Handled below.
|
| - status = DM_STATUS_RESPONSE_DECODING_ERROR;
|
| - }
|
| -
|
| - SampleErrorStatus(status);
|
| -
|
| - switch (status) {
|
| - case DM_STATUS_SUCCESS: {
|
| - const em::DevicePolicyResponse& policy_response(
|
| - response.policy_response());
|
| - if (policy_response.response_size() > 0) {
|
| - if (policy_response.response_size() > 1) {
|
| - LOG(WARNING) << "More than one policy in the response of the device "
|
| - << "management server, discarding.";
|
| - }
|
| - const em::PolicyFetchResponse& fetch_response(
|
| - policy_response.response(0));
|
| - if (!fetch_response.has_error_code() ||
|
| - fetch_response.error_code() == dm_protocol::POLICY_FETCH_SUCCESS) {
|
| - if (cache_->SetPolicy(fetch_response))
|
| - SetState(STATE_POLICY_VALID);
|
| - else
|
| - SetState(STATE_POLICY_ERROR);
|
| - } else {
|
| - UMA_HISTOGRAM_ENUMERATION(kMetricPolicy,
|
| - kMetricPolicyFetchBadResponse,
|
| - kMetricPolicySize);
|
| - SetState(STATE_POLICY_UNAVAILABLE);
|
| - }
|
| - } else {
|
| - UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchBadResponse,
|
| - kMetricPolicySize);
|
| - SetState(STATE_POLICY_UNAVAILABLE);
|
| - }
|
| - return;
|
| - }
|
| - case DM_STATUS_SERVICE_DEVICE_NOT_FOUND:
|
| - case DM_STATUS_SERVICE_DEVICE_ID_CONFLICT:
|
| - case DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID:
|
| - LOG(WARNING) << "The device token was either invalid or unknown to the "
|
| - << "device manager, re-registering device.";
|
| - // Will retry fetching a token but gracefully backing off.
|
| - SetState(STATE_TOKEN_ERROR);
|
| - return;
|
| - case DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER:
|
| - VLOG(1) << "The device is no longer enlisted for the domain.";
|
| - token_fetcher_->SetSerialNumberInvalidState();
|
| - SetState(STATE_TOKEN_ERROR);
|
| - return;
|
| - case DM_STATUS_SERVICE_MISSING_LICENSES:
|
| - VLOG(1) << "There are no valid licenses for this domain left.";
|
| - token_fetcher_->SetMissingLicensesState();
|
| - SetState(STATE_TOKEN_UNMANAGED);
|
| - return;
|
| - case DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED:
|
| - VLOG(1) << "The device is no longer managed.";
|
| - token_fetcher_->SetUnmanagedState();
|
| - SetState(STATE_TOKEN_UNMANAGED);
|
| - return;
|
| - case DM_STATUS_SERVICE_POLICY_NOT_FOUND:
|
| - case DM_STATUS_REQUEST_INVALID:
|
| - case DM_STATUS_SERVICE_ACTIVATION_PENDING:
|
| - case DM_STATUS_RESPONSE_DECODING_ERROR:
|
| - case DM_STATUS_HTTP_STATUS_ERROR:
|
| - VLOG(1) << "An error in the communication with the policy server occurred"
|
| - << ", will retry in a few hours.";
|
| - SetState(STATE_POLICY_UNAVAILABLE);
|
| - return;
|
| - case DM_STATUS_REQUEST_FAILED:
|
| - case DM_STATUS_TEMPORARY_UNAVAILABLE:
|
| - VLOG(1) << "A temporary error in the communication with the policy server"
|
| - << " occurred.";
|
| - // Will retry last operation but gracefully backing off.
|
| - SetState(STATE_POLICY_ERROR);
|
| - return;
|
| - }
|
| -
|
| - NOTREACHED();
|
| - SetState(STATE_POLICY_ERROR);
|
| -}
|
| -
|
| -void CloudPolicyController::OnDeviceTokenChanged() {
|
| - if (data_store_->device_token().empty()) {
|
| - // Additionally clear the generated device id to ensure we don't reuse old
|
| - // ids which could be potentially used for user tracking.
|
| - data_store_->set_device_id(std::string());
|
| - SetState(STATE_TOKEN_UNAVAILABLE);
|
| - } else {
|
| - SetState(STATE_TOKEN_VALID);
|
| - }
|
| -}
|
| -
|
| -void CloudPolicyController::OnCredentialsChanged() {
|
| - // This notification is only interesting if we don't have a device token.
|
| - // If we already have a device token, that must be matching the current
|
| - // user, because (1) we always recreate the policy subsystem after user
|
| - // login (2) tokens are cached per user.
|
| - if (data_store_->device_token().empty()) {
|
| - notifier_->Inform(CloudPolicySubsystem::UNENROLLED,
|
| - CloudPolicySubsystem::NO_DETAILS,
|
| - PolicyNotifier::POLICY_CONTROLLER);
|
| - effective_policy_refresh_error_delay_ms_ =
|
| - kPolicyRefreshErrorDelayInMilliseconds;
|
| - SetState(STATE_TOKEN_UNAVAILABLE);
|
| - }
|
| -}
|
| -
|
| -CloudPolicyController::CloudPolicyController(
|
| - DeviceManagementService* service,
|
| - CloudPolicyCacheBase* cache,
|
| - DeviceTokenFetcher* token_fetcher,
|
| - CloudPolicyDataStore* data_store,
|
| - PolicyNotifier* notifier,
|
| - DelayedWorkScheduler* scheduler) {
|
| - Initialize(service,
|
| - cache,
|
| - token_fetcher,
|
| - data_store,
|
| - notifier,
|
| - scheduler);
|
| -}
|
| -
|
| -void CloudPolicyController::Initialize(
|
| - DeviceManagementService* service,
|
| - CloudPolicyCacheBase* cache,
|
| - DeviceTokenFetcher* token_fetcher,
|
| - CloudPolicyDataStore* data_store,
|
| - PolicyNotifier* notifier,
|
| - DelayedWorkScheduler* scheduler) {
|
| - DCHECK(cache);
|
| -
|
| - service_ = service;
|
| - cache_ = cache;
|
| - token_fetcher_ = token_fetcher;
|
| - data_store_ = data_store;
|
| - notifier_ = notifier;
|
| - state_ = STATE_TOKEN_UNAVAILABLE;
|
| - policy_refresh_rate_ms_ = kPolicyRefreshRateInMilliseconds;
|
| - effective_policy_refresh_error_delay_ms_ =
|
| - kPolicyRefreshErrorDelayInMilliseconds;
|
| - scheduler_.reset(scheduler);
|
| - data_store_->AddObserver(this);
|
| - if (!data_store_->device_token().empty())
|
| - SetState(STATE_TOKEN_VALID);
|
| - else
|
| - SetState(STATE_TOKEN_UNAVAILABLE);
|
| -}
|
| -
|
| -bool CloudPolicyController::ReadyToFetchToken() {
|
| - return data_store_->token_cache_loaded() &&
|
| - !data_store_->user_name().empty() &&
|
| - data_store_->has_auth_token();
|
| -}
|
| -
|
| -void CloudPolicyController::FetchToken() {
|
| - if (ReadyToFetchToken()) {
|
| - if (BrowserPolicyConnector::IsNonEnterpriseUser(data_store_->user_name())) {
|
| - SetState(STATE_TOKEN_UNMANAGED);
|
| - } else {
|
| - // Either use an already prepopulated id or generate a new random device
|
| - // id. (It'll only be kept if registration succeeds.)
|
| - if (data_store_->device_id().empty())
|
| - data_store_->set_device_id(base::GenerateGUID());
|
| - token_fetcher_->FetchToken();
|
| - }
|
| - } else {
|
| - VLOG(1) << "Not ready to fetch DMToken yet, will try again later.";
|
| - }
|
| -}
|
| -
|
| -void CloudPolicyController::SendPolicyRequest() {
|
| - DCHECK(!data_store_->device_token().empty());
|
| -
|
| - if (!data_store_->policy_fetching_enabled())
|
| - return;
|
| -
|
| - request_job_.reset(
|
| - service_->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH));
|
| - request_job_->SetDMToken(data_store_->device_token());
|
| - request_job_->SetClientID(data_store_->device_id());
|
| - request_job_->SetUserAffiliation(data_store_->user_affiliation());
|
| -
|
| - em::DeviceManagementRequest* request = request_job_->GetRequest();
|
| - em::PolicyFetchRequest* fetch_request =
|
| - request->mutable_policy_request()->add_request();
|
| - fetch_request->set_signature_type(em::PolicyFetchRequest::SHA1_RSA);
|
| - fetch_request->set_policy_type(data_store_->policy_type());
|
| - if (cache_->machine_id_missing() && !data_store_->machine_id().empty())
|
| - fetch_request->set_machine_id(data_store_->machine_id());
|
| - if (!cache_->is_unmanaged() &&
|
| - !cache_->last_policy_refresh_time().is_null()) {
|
| - base::TimeDelta timestamp =
|
| - cache_->last_policy_refresh_time() - base::Time::UnixEpoch();
|
| - fetch_request->set_timestamp(timestamp.InMilliseconds());
|
| - }
|
| - int key_version = 0;
|
| - if (cache_->GetPublicKeyVersion(&key_version))
|
| - fetch_request->set_public_key_version(key_version);
|
| -
|
| -#if defined(OS_CHROMEOS)
|
| - if (data_store_->device_status_collector()) {
|
| - data_store_->device_status_collector()->GetStatus(
|
| - request->mutable_device_status_report_request());
|
| - }
|
| -#endif
|
| -
|
| - request_job_->Start(base::Bind(&CloudPolicyController::OnPolicyFetchCompleted,
|
| - base::Unretained(this)));
|
| - UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchRequested,
|
| - kMetricPolicySize);
|
| -}
|
| -
|
| -void CloudPolicyController::DoWork() {
|
| - switch (state_) {
|
| - case STATE_TOKEN_UNAVAILABLE:
|
| - case STATE_TOKEN_ERROR:
|
| - FetchToken();
|
| - return;
|
| - case STATE_TOKEN_VALID:
|
| - case STATE_POLICY_VALID:
|
| - case STATE_POLICY_ERROR:
|
| - case STATE_POLICY_UNAVAILABLE:
|
| - SendPolicyRequest();
|
| - return;
|
| - case STATE_TOKEN_UNMANAGED:
|
| - return;
|
| - }
|
| -
|
| - NOTREACHED() << "Unhandled state" << state_;
|
| -}
|
| -
|
| -void CloudPolicyController::SetState(
|
| - CloudPolicyController::ControllerState new_state) {
|
| - state_ = new_state;
|
| -
|
| - request_job_.reset(); // Stop any pending requests.
|
| -
|
| - base::Time now(base::Time::NowFromSystemTime());
|
| - base::Time last_refresh(GetLastRefreshTime(now));
|
| - base::Time refresh_at;
|
| -
|
| - // Determine when to take the next step.
|
| - bool inform_notifier_done = false;
|
| - switch (state_) {
|
| - case STATE_TOKEN_UNMANAGED:
|
| - notifier_->Inform(CloudPolicySubsystem::UNMANAGED,
|
| - CloudPolicySubsystem::NO_DETAILS,
|
| - PolicyNotifier::POLICY_CONTROLLER);
|
| - break;
|
| - case STATE_TOKEN_UNAVAILABLE:
|
| - // The controller is not yet initialized and needs to immediately fetch
|
| - // token and policy if present.
|
| - case STATE_TOKEN_VALID:
|
| - // Immediately try to fetch the token on initialization or policy after a
|
| - // token update. Subsequent retries will respect the back-off strategy.
|
| - refresh_at = now;
|
| - // |notifier_| isn't informed about anything at this point, we wait for
|
| - // the result of the next action first.
|
| - break;
|
| - case STATE_POLICY_VALID:
|
| - // Delay is only reset if the policy fetch operation was successful. This
|
| - // will ensure the server won't get overloaded with retries in case of
|
| - // a bug on either side.
|
| - effective_policy_refresh_error_delay_ms_ =
|
| - kPolicyRefreshErrorDelayInMilliseconds;
|
| - refresh_at = last_refresh + GetRefreshDelay();
|
| - notifier_->Inform(CloudPolicySubsystem::SUCCESS,
|
| - CloudPolicySubsystem::NO_DETAILS,
|
| - PolicyNotifier::POLICY_CONTROLLER);
|
| - break;
|
| - case STATE_TOKEN_ERROR:
|
| - notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
|
| - CloudPolicySubsystem::BAD_DMTOKEN,
|
| - PolicyNotifier::POLICY_CONTROLLER);
|
| - inform_notifier_done = true;
|
| - case STATE_POLICY_ERROR:
|
| - if (!inform_notifier_done) {
|
| - notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
|
| - CloudPolicySubsystem::POLICY_NETWORK_ERROR,
|
| - PolicyNotifier::POLICY_CONTROLLER);
|
| - }
|
| - refresh_at = now + base::TimeDelta::FromMilliseconds(
|
| - effective_policy_refresh_error_delay_ms_);
|
| - effective_policy_refresh_error_delay_ms_ =
|
| - std::min(effective_policy_refresh_error_delay_ms_ * 2,
|
| - policy_refresh_rate_ms_);
|
| - break;
|
| - case STATE_POLICY_UNAVAILABLE:
|
| - effective_policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_;
|
| - refresh_at = now + base::TimeDelta::FromMilliseconds(
|
| - effective_policy_refresh_error_delay_ms_);
|
| - notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR,
|
| - CloudPolicySubsystem::POLICY_NETWORK_ERROR,
|
| - PolicyNotifier::POLICY_CONTROLLER);
|
| - break;
|
| - }
|
| -
|
| - // Update the delayed work task.
|
| - scheduler_->CancelDelayedWork();
|
| - if (!refresh_at.is_null())
|
| - ScheduleDelayedWorkTask(refresh_at - now);
|
| -
|
| - // Inform the cache if a fetch attempt has completed. This happens if policy
|
| - // has been succesfully fetched, or if token or policy fetching failed.
|
| - if (state_ != STATE_TOKEN_UNAVAILABLE && state_ != STATE_TOKEN_VALID)
|
| - cache_->SetFetchingDone();
|
| -}
|
| -
|
| -base::TimeDelta CloudPolicyController::GetRefreshDelay() {
|
| - int64 deviation = (kPolicyRefreshDeviationFactorPercent *
|
| - policy_refresh_rate_ms_) / 100;
|
| - deviation = std::min(deviation, kPolicyRefreshDeviationMaxInMilliseconds);
|
| - return base::TimeDelta::FromMilliseconds(
|
| - policy_refresh_rate_ms_ - base::RandGenerator(deviation + 1));
|
| -}
|
| -
|
| -void CloudPolicyController::ScheduleDelayedWorkTask(
|
| - const base::TimeDelta& delay) {
|
| - int64 effective_delay = std::max<int64>(delay.InMilliseconds(), 0);
|
| - scheduler_->PostDelayedWork(
|
| - base::Bind(&CloudPolicyController::DoWork, base::Unretained(this)),
|
| - effective_delay);
|
| -}
|
| -
|
| -base::Time CloudPolicyController::GetLastRefreshTime(const base::Time& now) {
|
| - base::Time last_refresh(cache_->last_policy_refresh_time());
|
| - if (last_refresh.is_null())
|
| - last_refresh = now;
|
| -
|
| - return last_refresh;
|
| -}
|
| -
|
| -} // namespace policy
|
|
|