Chromium Code Reviews| 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..1d23ac10c1d4706aa7453d00c0abd1c9767ad3ec |
| --- /dev/null |
| +++ b/chrome/browser/policy/cloud_policy_client.cc |
| @@ -0,0 +1,277 @@ |
| +// 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 |
|
danno
2011/02/04 16:01:33
s/its/it's/
Jakob Kummerow
2011/02/14 13:50:34
Done.
|
| +// 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. |
| +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 = 3 * 1000; // 3 seconds |
| + |
| +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, |
| + CloudPolicyContext::kDefaultPolicyRefreshRateInMilliseconds, |
| + 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 |