blob: 5e59294b98810c0a048cb4c905e9e0295c01ff06 [file] [log] [blame]
// 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/chromeos/policy/device_local_account_policy_service.h"
#include <vector>
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
#include "chrome/browser/chromeos/policy/device_local_account.h"
#include "chrome/browser/chromeos/policy/device_local_account_policy_store.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/device_settings_service.h"
#include "chrome/browser/policy/cloud/cloud_policy_client.h"
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
#include "chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h"
#include "chrome/browser/policy/cloud/device_management_service.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
#include "chromeos/dbus/session_manager_client.h"
#include "chromeos/settings/cros_settings_names.h"
#include "chromeos/settings/cros_settings_provider.h"
#include "policy/policy_constants.h"
namespace em = enterprise_management;
namespace policy {
namespace {
// Creates and initializes a cloud policy client. Returns NULL if the device
// doesn't have credentials in device settings (i.e. is not
// enterprise-enrolled).
scoped_ptr<CloudPolicyClient> CreateClient(
chromeos::DeviceSettingsService* device_settings_service,
DeviceManagementService* device_management_service) {
const em::PolicyData* policy_data = device_settings_service->policy_data();
if (!policy_data ||
!policy_data->has_request_token() ||
!policy_data->has_device_id() ||
!device_management_service) {
return scoped_ptr<CloudPolicyClient>();
}
scoped_ptr<CloudPolicyClient> client(
new CloudPolicyClient(std::string(), std::string(),
USER_AFFILIATION_MANAGED,
NULL, device_management_service));
client->SetupRegistration(policy_data->request_token(),
policy_data->device_id());
return client.Pass();
}
} // namespace
DeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker(
const std::string& user_id,
scoped_ptr<DeviceLocalAccountPolicyStore> store,
const scoped_refptr<base::SequencedTaskRunner>& task_runner)
: user_id_(user_id),
store_(store.Pass()),
core_(PolicyNamespaceKey(dm_protocol::kChromePublicAccountPolicyType,
store_->account_id()),
store_.get(),
task_runner) {}
DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {}
void DeviceLocalAccountPolicyBroker::Connect(
scoped_ptr<CloudPolicyClient> client) {
core_.Connect(client.Pass());
core_.StartRefreshScheduler();
UpdateRefreshDelay();
}
void DeviceLocalAccountPolicyBroker::Disconnect() {
core_.Disconnect();
}
void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() {
if (core_.refresh_scheduler()) {
const Value* policy_value =
store_->policy_map().GetValue(key::kPolicyRefreshRate);
int delay = 0;
if (policy_value && policy_value->GetAsInteger(&delay))
core_.refresh_scheduler()->SetRefreshDelay(delay);
}
}
std::string DeviceLocalAccountPolicyBroker::GetDisplayName() const {
std::string display_name;
const base::Value* display_name_value =
store_->policy_map().GetValue(policy::key::kUserDisplayName);
if (display_name_value)
display_name_value->GetAsString(&display_name);
return display_name;
}
DeviceLocalAccountPolicyService::PolicyBrokerWrapper::PolicyBrokerWrapper()
: parent(NULL), broker(NULL) {}
DeviceLocalAccountPolicyBroker*
DeviceLocalAccountPolicyService::PolicyBrokerWrapper::GetBroker() {
if (!broker) {
scoped_ptr<DeviceLocalAccountPolicyStore> store(
new DeviceLocalAccountPolicyStore(account_id,
parent->session_manager_client_,
parent->device_settings_service_));
broker = new DeviceLocalAccountPolicyBroker(
user_id, store.Pass(), base::MessageLoopProxy::current());
broker->core()->store()->AddObserver(parent);
broker->core()->store()->Load();
}
return broker;
}
void DeviceLocalAccountPolicyService::PolicyBrokerWrapper::ConnectIfPossible() {
if (broker && broker->core()->client())
return;
scoped_ptr<CloudPolicyClient> client(CreateClient(
parent->device_settings_service_,
parent->device_management_service_));
if (client)
GetBroker()->Connect(client.Pass());
}
void DeviceLocalAccountPolicyService::PolicyBrokerWrapper::Disconnect() {
if (broker)
broker->Disconnect();
}
void DeviceLocalAccountPolicyService::PolicyBrokerWrapper::DeleteBroker() {
if (!broker)
return;
broker->core()->store()->RemoveObserver(parent);
delete broker;
broker = NULL;
}
DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
chromeos::SessionManagerClient* session_manager_client,
chromeos::DeviceSettingsService* device_settings_service,
chromeos::CrosSettings* cros_settings)
: session_manager_client_(session_manager_client),
device_settings_service_(device_settings_service),
cros_settings_(cros_settings),
device_management_service_(NULL),
cros_settings_callback_factory_(this) {
local_accounts_subscription_ = cros_settings_->AddSettingsObserver(
chromeos::kAccountsPrefDeviceLocalAccounts,
base::Bind(&DeviceLocalAccountPolicyService::
UpdateAccountListIfNonePending,
base::Unretained(this)));
UpdateAccountList();
}
DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() {
DeleteBrokers(&policy_brokers_);
}
void DeviceLocalAccountPolicyService::Connect(
DeviceManagementService* device_management_service) {
DCHECK(!device_management_service_);
device_management_service_ = device_management_service;
// Connect the brokers.
for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
it != policy_brokers_.end(); ++it) {
it->second.ConnectIfPossible();
}
}
void DeviceLocalAccountPolicyService::Disconnect() {
DCHECK(device_management_service_);
device_management_service_ = NULL;
// Disconnect the brokers.
for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
it != policy_brokers_.end(); ++it) {
it->second.Disconnect();
}
}
DeviceLocalAccountPolicyBroker*
DeviceLocalAccountPolicyService::GetBrokerForUser(
const std::string& user_id) {
PolicyBrokerMap::iterator entry = policy_brokers_.find(user_id);
if (entry == policy_brokers_.end())
return NULL;
return entry->second.GetBroker();
}
bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser(
const std::string& user_id) {
DeviceLocalAccountPolicyBroker* broker = GetBrokerForUser(user_id);
return broker && broker->core()->store()->is_managed();
}
void DeviceLocalAccountPolicyService::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void DeviceLocalAccountPolicyService::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void DeviceLocalAccountPolicyService::OnStoreLoaded(CloudPolicyStore* store) {
DeviceLocalAccountPolicyBroker* broker = GetBrokerForStore(store);
DCHECK(broker);
if (!broker)
return;
broker->UpdateRefreshDelay();
FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(broker->user_id()));
}
void DeviceLocalAccountPolicyService::OnStoreError(CloudPolicyStore* store) {
DeviceLocalAccountPolicyBroker* broker = GetBrokerForStore(store);
DCHECK(broker);
if (!broker)
return;
FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(broker->user_id()));
}
void DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending() {
// Avoid unnecessary calls to UpdateAccountList(): If an earlier call is still
// pending (because the |cros_settings_| are not trusted yet), the updated
// account list will be processed by that call when it eventually runs.
if (!cros_settings_callback_factory_.HasWeakPtrs())
UpdateAccountList();
}
void DeviceLocalAccountPolicyService::UpdateAccountList() {
if (chromeos::CrosSettingsProvider::TRUSTED !=
cros_settings_->PrepareTrustedValues(
base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList,
cros_settings_callback_factory_.GetWeakPtr()))) {
return;
}
// Update |policy_brokers_|, keeping existing entries.
PolicyBrokerMap old_policy_brokers;
policy_brokers_.swap(old_policy_brokers);
const std::vector<DeviceLocalAccount> device_local_accounts =
GetDeviceLocalAccounts(cros_settings_);
for (std::vector<DeviceLocalAccount>::const_iterator it =
device_local_accounts.begin();
it != device_local_accounts.end(); ++it) {
PolicyBrokerWrapper& wrapper = policy_brokers_[it->user_id];
wrapper.user_id = it->user_id;
wrapper.account_id = it->account_id;
wrapper.parent = this;
// Reuse the existing broker if present.
PolicyBrokerWrapper& existing_wrapper = old_policy_brokers[it->user_id];
wrapper.broker = existing_wrapper.broker;
existing_wrapper.broker = NULL;
// Fire up the cloud connection for fetching policy for the account from
// the cloud if this is an enterprise-managed device.
wrapper.ConnectIfPossible();
}
DeleteBrokers(&old_policy_brokers);
FOR_EACH_OBSERVER(Observer, observers_, OnDeviceLocalAccountsChanged());
}
void DeviceLocalAccountPolicyService::DeleteBrokers(PolicyBrokerMap* map) {
for (PolicyBrokerMap::iterator it = map->begin(); it != map->end(); ++it)
it->second.DeleteBroker();
map->clear();
}
DeviceLocalAccountPolicyBroker*
DeviceLocalAccountPolicyService::GetBrokerForStore(
CloudPolicyStore* store) {
for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
it != policy_brokers_.end(); ++it) {
if (it->second.broker && it->second.broker->core()->store() == store)
return it->second.broker;
}
return NULL;
}
} // namespace policy