| Index: chrome/browser/policy/cloud_policy_client.cc
|
| diff --git a/chrome/browser/policy/cloud_policy_client.cc b/chrome/browser/policy/cloud_policy_client.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c325bf08b8dbd672e34bb13624fd2601a012121f
|
| --- /dev/null
|
| +++ b/chrome/browser/policy/cloud_policy_client.cc
|
| @@ -0,0 +1,282 @@
|
| +// Copyright (c) 2011 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_client.h"
|
| +
|
| +#include "base/message_loop.h"
|
| +#include "base/rand_util.h"
|
| +#include "base/string_util.h"
|
| +#include "chrome/browser/policy/cloud_policy_cache.h"
|
| +#include "chrome/browser/policy/cloud_policy_context.h"
|
| +#include "chrome/browser/policy/device_management_backend.h"
|
| +#include "chrome/browser/policy/proto/device_management_constants.h"
|
| +
|
| +// Domain names that are known not to be managed.
|
| +// We don't register the device when such a user logs in.
|
| +static const char* kNonManagedDomains[] = {
|
| + "@googlemail.com",
|
| + "@gmail.com"
|
| +};
|
| +
|
| +// Checks the domain part of the given username against the list of known
|
| +// non-managed domain names. Returns false if |username| is empty or its
|
| +// in a domain known not to be managed.
|
| +static bool CanBeInManagedDomain(const std::string& username) {
|
| + if (username.empty()) {
|
| + // This means incognito user in case of ChromiumOS and
|
| + // no logged-in user in case of Chromium (SigninService).
|
| + return false;
|
| + }
|
| + for (size_t i = 0; i < arraysize(kNonManagedDomains); i++) {
|
| + if (EndsWith(username, kNonManagedDomains[i], true)) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +namespace policy {
|
| +
|
| +namespace em = enterprise_management;
|
| +
|
| +// 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.
|
| +static const int kPolicyRefreshDeviationFactorPercent = 10;
|
| +// Maximum deviation we are willing to accept.
|
| +static 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.
|
| +static const int64 kPolicyRefreshErrorDelayInMilliseconds =
|
| + 3 * 1000; // 3 seconds
|
| +
|
| +// Default value for the policy refresh rate.
|
| +static const int kPolicyRefreshRateInMilliseconds =
|
| + 3 * 60 * 60 * 1000; // 3 hours.
|
| +
|
| +CloudPolicyClient::CloudPolicyClient(CloudPolicyCache* cache,
|
| + DeviceManagementBackend* backend,
|
| + DeviceTokenFetcher* token_fetcher,
|
| + CloudPolicyController* controller)
|
| + : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
|
| + Initialize(cache,
|
| + backend,
|
| + token_fetcher,
|
| + controller,
|
| + kPolicyRefreshRateInMilliseconds,
|
| + kPolicyRefreshDeviationFactorPercent,
|
| + kPolicyRefreshDeviationMaxInMilliseconds,
|
| + kPolicyRefreshErrorDelayInMilliseconds);
|
| +}
|
| +
|
| +CloudPolicyClient::~CloudPolicyClient() {
|
| + token_fetcher_->RemoveObserver(this);
|
| + controller_->RemoveObserver(this);
|
| + CancelDelayedWork();
|
| +}
|
| +
|
| +void CloudPolicyClient::SetRefreshRate(int64 refresh_rate_milliseconds) {
|
| + policy_refresh_rate_ms_ = refresh_rate_milliseconds;
|
| +
|
| + // Reschedule the refresh task if necessary.
|
| + if (state_ == STATE_POLICY_VALID)
|
| + SetState(STATE_POLICY_VALID);
|
| +}
|
| +
|
| +void CloudPolicyClient::HandlePolicyResponse(
|
| + const em::DevicePolicyResponse& response) {
|
| + if (state_ == STATE_TOKEN_UNAVAILABLE)
|
| + return;
|
| +
|
| + cache_->SetPolicy(response);
|
| + SetState(STATE_POLICY_VALID);
|
| +}
|
| +
|
| +void CloudPolicyClient::OnError(DeviceManagementBackend::ErrorCode code) {
|
| + if (state_ == STATE_TOKEN_UNAVAILABLE)
|
| + return;
|
| +
|
| + if (code == DeviceManagementBackend::kErrorServiceDeviceNotFound ||
|
| + code == DeviceManagementBackend::kErrorServiceManagementTokenInvalid) {
|
| + LOG(WARNING) << "The device token was either invalid or unknown to the "
|
| + << "device manager, re-registering device.";
|
| + SetState(STATE_TOKEN_UNAVAILABLE);
|
| + } else if (code ==
|
| + DeviceManagementBackend::kErrorServiceManagementNotSupported) {
|
| + VLOG(1) << "The device is no longer managed, resetting device token.";
|
| + SetState(STATE_TOKEN_UNAVAILABLE);
|
| + } else {
|
| + LOG(WARNING) << "Could not provide policy from the device manager (error = "
|
| + << code << "), will retry in "
|
| + << (effective_policy_refresh_error_delay_ms_ / 1000)
|
| + << " seconds.";
|
| + SetState(STATE_POLICY_ERROR);
|
| + }
|
| +}
|
| +
|
| +void CloudPolicyClient::OnTokenAvailable() {
|
| + controller_->OnTokenAvailable(token_fetcher_->GetDeviceToken());
|
| +}
|
| +
|
| +void CloudPolicyClient::OnTokenChanged() {
|
| + if (controller_->GetDeviceToken().empty())
|
| + SetState(STATE_TOKEN_UNAVAILABLE);
|
| + else
|
| + SetState(STATE_TOKEN_VALID);
|
| +}
|
| +
|
| +void CloudPolicyClient::OnCredentialsChanged() {
|
| + SetState(STATE_TOKEN_UNAVAILABLE);
|
| +}
|
| +
|
| +CloudPolicyClient::CloudPolicyClient(
|
| + CloudPolicyCache* cache,
|
| + DeviceManagementBackend* backend,
|
| + DeviceTokenFetcher* token_fetcher,
|
| + CloudPolicyController* controller,
|
| + int64 policy_refresh_rate_ms,
|
| + int policy_refresh_deviation_factor_percent,
|
| + int64 policy_refresh_deviation_max_ms,
|
| + int64 policy_refresh_error_delay_ms)
|
| + : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
|
| + Initialize(cache,
|
| + backend,
|
| + token_fetcher,
|
| + controller,
|
| + policy_refresh_rate_ms,
|
| + policy_refresh_deviation_factor_percent,
|
| + policy_refresh_deviation_max_ms,
|
| + policy_refresh_error_delay_ms);
|
| +}
|
| +
|
| +void CloudPolicyClient::Initialize(
|
| + CloudPolicyCache* cache,
|
| + DeviceManagementBackend* backend,
|
| + DeviceTokenFetcher* token_fetcher,
|
| + CloudPolicyController* controller,
|
| + int64 policy_refresh_rate_ms,
|
| + int policy_refresh_deviation_factor_percent,
|
| + int64 policy_refresh_deviation_max_ms,
|
| + int64 policy_refresh_error_delay_ms) {
|
| + DCHECK(cache);
|
| +
|
| + cache_ = cache;
|
| + backend_.reset(backend);
|
| + token_fetcher_ = token_fetcher;
|
| + controller_ = controller;
|
| + state_ = STATE_TOKEN_UNAVAILABLE;
|
| + delayed_work_task_ = NULL;
|
| + policy_refresh_rate_ms_ = policy_refresh_rate_ms;
|
| + policy_refresh_deviation_factor_percent_ =
|
| + policy_refresh_deviation_factor_percent;
|
| + policy_refresh_deviation_max_ms_ = policy_refresh_deviation_max_ms;
|
| + policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms;
|
| + effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms;
|
| +
|
| + token_fetcher_->AddObserver(this);
|
| + controller_->AddObserver(this);
|
| + if (!controller_->GetDeviceToken().empty())
|
| + SetState(STATE_TOKEN_VALID);
|
| + else
|
| + SetState(STATE_TOKEN_UNAVAILABLE);
|
| +}
|
| +
|
| +void CloudPolicyClient::FetchToken() {
|
| + token_fetcher_->Reset();
|
| +
|
| + std::string username;
|
| + std::string auth_token;
|
| + std::string device_id = controller_->GetDeviceID();
|
| + if (controller_->GetCredentials(&username, &auth_token) &&
|
| + CanBeInManagedDomain(username))
|
| + token_fetcher_->FetchToken(auth_token, device_id);
|
| +}
|
| +
|
| +void CloudPolicyClient::SendPolicyRequest() {
|
| + DCHECK(!controller_->GetDeviceToken().empty());
|
| + em::DevicePolicyRequest policy_request;
|
| + policy_request.set_policy_scope(kChromePolicyScope);
|
| + em::DevicePolicySettingRequest* setting =
|
| + policy_request.add_setting_request();
|
| + setting->set_key(kChromeDevicePolicySettingKey);
|
| + setting->set_watermark("");
|
| + backend_->ProcessPolicyRequest(controller_->GetDeviceToken(),
|
| + controller_->GetDeviceID(),
|
| + policy_request, this);
|
| +}
|
| +
|
| +void CloudPolicyClient::DoDelayedWork() {
|
| + DCHECK(delayed_work_task_);
|
| + delayed_work_task_ = NULL;
|
| +
|
| + switch (state_) {
|
| + case STATE_TOKEN_UNAVAILABLE:
|
| + FetchToken();
|
| + return;
|
| + case STATE_TOKEN_VALID:
|
| + case STATE_POLICY_VALID:
|
| + case STATE_POLICY_ERROR:
|
| + SendPolicyRequest();
|
| + return;
|
| + }
|
| +
|
| + NOTREACHED() << "Unhandled state" << state_;
|
| +}
|
| +
|
| +void CloudPolicyClient::CancelDelayedWork() {
|
| + if (delayed_work_task_) {
|
| + delayed_work_task_->Cancel();
|
| + delayed_work_task_ = NULL;
|
| + }
|
| +}
|
| +
|
| +void CloudPolicyClient::SetState(CloudPolicyClient::ClientState new_state) {
|
| + state_ = new_state;
|
| +
|
| + base::Time now(base::Time::NowFromSystemTime());
|
| + base::Time refresh_at;
|
| + base::Time last_refresh(cache_->last_policy_refresh_time());
|
| + if (last_refresh.is_null())
|
| + last_refresh = now;
|
| +
|
| + // Determine when to take the next step.
|
| + switch (state_) {
|
| + case STATE_TOKEN_UNAVAILABLE:
|
| + case STATE_TOKEN_VALID:
|
| + refresh_at = now;
|
| + break;
|
| + case STATE_POLICY_VALID:
|
| + effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms_;
|
| + refresh_at =
|
| + last_refresh + base::TimeDelta::FromMilliseconds(GetRefreshDelay());
|
| + break;
|
| + case STATE_POLICY_ERROR:
|
| + refresh_at = now + base::TimeDelta::FromMilliseconds(
|
| + effective_policy_refresh_error_delay_ms_);
|
| + effective_policy_refresh_error_delay_ms_ *= 2;
|
| + if (effective_policy_refresh_error_delay_ms_ > policy_refresh_rate_ms_)
|
| + effective_policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_;
|
| + break;
|
| + }
|
| +
|
| + // Update the delayed work task.
|
| + CancelDelayedWork();
|
| + if (!refresh_at.is_null()) {
|
| + int64 delay = std::max<int64>((refresh_at - now).InMilliseconds(), 0);
|
| + delayed_work_task_ =
|
| + method_factory_.NewRunnableMethod(&CloudPolicyClient::DoDelayedWork);
|
| + MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_work_task_,
|
| + delay);
|
| + }
|
| +}
|
| +
|
| +int64 CloudPolicyClient::GetRefreshDelay() {
|
| + int64 deviation = (policy_refresh_deviation_factor_percent_ *
|
| + policy_refresh_rate_ms_) / 100;
|
| + deviation = std::min(deviation, policy_refresh_deviation_max_ms_);
|
| + return policy_refresh_rate_ms_ - base::RandGenerator(deviation + 1);
|
| +}
|
| +
|
| +} // namespace policy
|
|
|