device_local_account_policy_service.cc revision f2477e01787aa58f445919b809d89e252beef54f
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// found in the LICENSE file.
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <vector>
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/bind.h"
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/file_util.h"
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/files/file_enumerator.h"
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/files/file_path.h"
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/logging.h"
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/message_loop/message_loop.h"
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/path_service.h"
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/sequenced_task_runner.h"
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/chromeos/policy/device_local_account.h"
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/chromeos/policy/device_local_account_external_data_service.h"
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/chromeos/policy/device_local_account_policy_store.h"
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/chromeos/settings/device_settings_service.h"
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/policy/cloud/cloud_policy_client.h"
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h"
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/policy/cloud/device_management_service.h"
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chromeos/chromeos_paths.h"
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chromeos/dbus/session_manager_client.h"
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chromeos/settings/cros_settings_names.h"
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chromeos/settings/cros_settings_provider.h"
32f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu#include "net/url_request/url_request_context_getter.h"
33f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu#include "policy/policy_constants.h"
34197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
3553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)namespace em = enterprise_management;
369e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)
3753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)namespace policy {
387242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
39e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)namespace {
4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
4153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)// Creates and initializes a cloud policy client. Returns NULL if the device
425267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// doesn't have credentials in device settings (i.e. is not
43f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu// enterprise-enrolled).
44591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdochscoped_ptr<CloudPolicyClient> CreateClient(
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    chromeos::DeviceSettingsService* device_settings_service,
4651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    DeviceManagementService* device_management_service) {
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  const em::PolicyData* policy_data = device_settings_service->policy_data();
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  if (!policy_data ||
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      !policy_data->has_request_token() ||
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      !policy_data->has_device_id() ||
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      !device_management_service) {
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return scoped_ptr<CloudPolicyClient>();
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  scoped_ptr<CloudPolicyClient> client(
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      new CloudPolicyClient(std::string(), std::string(),
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            USER_AFFILIATION_MANAGED,
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            NULL, device_management_service));
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  client->SetupRegistration(policy_data->request_token(),
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            policy_data->device_id());
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return client.Pass();
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Get the subdirectory of the cache directory in which force-installed
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// extensions are cached for |account_id|.
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)std::string GetCacheSubdirectoryForAccountID(const std::string& account_id) {
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return base::HexEncode(account_id.c_str(), account_id.size());
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Cleans up the cache directory by removing subdirectories that are not found
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// in |subdirectories_to_keep|. Only caches whose cache directory is found in
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// |subdirectories_to_keep| may be running while the clean-up is in progress.
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void DeleteOrphanedExtensionCaches(
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const std::set<std::string>& subdirectories_to_keep) {
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  base::FilePath cache_root_dir;
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                         &cache_root_dir));
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  base::FileEnumerator enumerator(cache_root_dir,
79926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                                  false,
80926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                                  base::FileEnumerator::DIRECTORIES);
811fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch  for (base::FilePath path = enumerator.Next(); !path.empty();
821fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch       path = enumerator.Next()) {
837242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    const std::string subdirectory(path.BaseName().MaybeAsASCII());
84926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (subdirectories_to_keep.find(subdirectory) ==
85926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        subdirectories_to_keep.end()) {
86926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)      base::DeleteFile(path, true);
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Removes the subdirectory belonging to |account_id_to_delete| from the cache
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// directory. No cache belonging to |account_id_to_delete| may be running while
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// the removal is in progress.
941fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdochvoid DeleteObsoleteExtensionCache(const std::string& account_id_to_delete) {
951fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch  base::FilePath cache_root_dir;
967242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
9751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)                         &cache_root_dir));
9851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)  const base::FilePath path = cache_root_dir
9951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)      .Append(GetCacheSubdirectoryForAccountID(account_id_to_delete));
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  if (base::DirectoryExists(path))
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    base::DeleteFile(path, true);
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}  // namespace
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
106197021e6b966cfb06891637935ef33fff06433d1Ben MurdochDeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker(
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const DeviceLocalAccount& account,
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    scoped_ptr<DeviceLocalAccountPolicyStore> store,
109926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    scoped_refptr<DeviceLocalAccountExternalDataManager> external_data_manager,
110926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
11181a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    : account_id_(account.account_id),
11281a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)      user_id_(account.user_id),
11381a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)      store_(store.Pass()),
11481a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)      external_data_manager_(external_data_manager),
115926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)      core_(PolicyNamespaceKey(dm_protocol::kChromePublicAccountPolicyType,
116926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                               store_->account_id()),
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            store_.get(),
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            task_runner) {
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  base::FilePath cache_root_dir;
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
121197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch                         &cache_root_dir));
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  extension_loader_ = new chromeos::DeviceLocalAccountExternalPolicyLoader(
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      store_.get(),
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      cache_root_dir.Append(
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          GetCacheSubdirectoryForAccountID(account.account_id)));
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
128197021e6b966cfb06891637935ef33fff06433d1Ben MurdochDeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  external_data_manager_->SetPolicyStore(NULL);
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  external_data_manager_->Disconnect();
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void DeviceLocalAccountPolicyBroker::Initialize() {
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  store_->Load();
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    chromeos::DeviceSettingsService* device_settings_service,
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DeviceManagementService* device_management_service,
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> request_context) {
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  if (core_.client())
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return;
143e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)
1449e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)  scoped_ptr<CloudPolicyClient> client(CreateClient(device_settings_service,
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                                    device_management_service));
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  if (!client)
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return;
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  core_.Connect(client.Pass());
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  external_data_manager_->Connect(request_context);
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  core_.StartRefreshScheduler();
152f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)  UpdateRefreshDelay();
153f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)}
154f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)
155f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() {
156f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)  if (core_.refresh_scheduler()) {
1579e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)    const Value* policy_value =
158f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)        store_->policy_map().GetValue(key::kPolicyRefreshRate);
159f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)    int delay = 0;
160f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)    if (policy_value && policy_value->GetAsInteger(&delay))
161f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)      core_.refresh_scheduler()->SetRefreshDelay(delay);
162f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)  }
163f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)}
164f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)
165f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)std::string DeviceLocalAccountPolicyBroker::GetDisplayName() const {
166f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)  std::string display_name;
167f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)  const base::Value* display_name_value =
168323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)      store_->policy_map().GetValue(policy::key::kUserDisplayName);
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  if (display_name_value)
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    display_name_value->GetAsString(&display_name);
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return display_name;
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
173323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    chromeos::SessionManagerClient* session_manager_client,
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    chromeos::DeviceSettingsService* device_settings_service,
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    chromeos::CrosSettings* cros_settings,
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
179323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner,
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner>
181926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        external_data_service_backend_task_runner,
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> request_context)
18451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    : session_manager_client_(session_manager_client),
185      device_settings_service_(device_settings_service),
186      cros_settings_(cros_settings),
187      device_management_service_(NULL),
188      waiting_for_cros_settings_(false),
189      orphan_cache_deletion_state_(NOT_STARTED),
190      store_background_task_runner_(store_background_task_runner),
191      extension_cache_task_runner_(extension_cache_task_runner),
192      request_context_(request_context),
193      local_accounts_subscription_(cros_settings_->AddSettingsObserver(
194          chromeos::kAccountsPrefDeviceLocalAccounts,
195          base::Bind(&DeviceLocalAccountPolicyService::
196                         UpdateAccountListIfNonePending,
197                     base::Unretained(this)))),
198      weak_factory_(this) {
199  external_data_service_.reset(new DeviceLocalAccountExternalDataService(
200      this,
201      external_data_service_backend_task_runner,
202      io_task_runner));
203  UpdateAccountList();
204}
205
206DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() {
207  DCHECK(!request_context_);
208  DCHECK(policy_brokers_.empty());
209}
210
211void DeviceLocalAccountPolicyService::Shutdown() {
212  device_management_service_ = NULL;
213  request_context_ = NULL;
214  DeleteBrokers(&policy_brokers_);
215}
216
217void DeviceLocalAccountPolicyService::Connect(
218    DeviceManagementService* device_management_service) {
219  DCHECK(!device_management_service_);
220  device_management_service_ = device_management_service;
221
222  // Connect the brokers.
223  for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
224       it != policy_brokers_.end(); ++it) {
225    it->second->ConnectIfPossible(device_settings_service_,
226                                  device_management_service_,
227                                  request_context_);
228  }
229}
230
231DeviceLocalAccountPolicyBroker*
232    DeviceLocalAccountPolicyService::GetBrokerForUser(
233        const std::string& user_id) {
234  PolicyBrokerMap::iterator entry = policy_brokers_.find(user_id);
235  if (entry == policy_brokers_.end())
236    return NULL;
237
238  return entry->second;
239}
240
241bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser(
242    const std::string& user_id) {
243  DeviceLocalAccountPolicyBroker* broker = GetBrokerForUser(user_id);
244  return broker && broker->core()->store()->is_managed();
245}
246
247void DeviceLocalAccountPolicyService::AddObserver(Observer* observer) {
248  observers_.AddObserver(observer);
249}
250
251void DeviceLocalAccountPolicyService::RemoveObserver(Observer* observer) {
252  observers_.RemoveObserver(observer);
253}
254
255void DeviceLocalAccountPolicyService::OnStoreLoaded(CloudPolicyStore* store) {
256  DeviceLocalAccountPolicyBroker* broker = GetBrokerForStore(store);
257  DCHECK(broker);
258  if (!broker)
259    return;
260  broker->UpdateRefreshDelay();
261  FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(broker->user_id()));
262}
263
264void DeviceLocalAccountPolicyService::OnStoreError(CloudPolicyStore* store) {
265  DeviceLocalAccountPolicyBroker* broker = GetBrokerForStore(store);
266  DCHECK(broker);
267  if (!broker)
268    return;
269  FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(broker->user_id()));
270}
271
272bool DeviceLocalAccountPolicyService::IsExtensionCacheDirectoryBusy(
273    const std::string& account_id) {
274  return busy_extension_cache_directories_.find(account_id) !=
275            busy_extension_cache_directories_.end();
276}
277
278void DeviceLocalAccountPolicyService::StartExtensionCachesIfPossible() {
279  for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
280       it != policy_brokers_.end(); ++it) {
281    if (!it->second->extension_loader()->IsCacheRunning() &&
282        !IsExtensionCacheDirectoryBusy(it->second->account_id())) {
283      it->second->extension_loader()->StartCache(extension_cache_task_runner_);
284    }
285  }
286}
287
288bool DeviceLocalAccountPolicyService::StartExtensionCacheForAccountIfPresent(
289    const std::string& account_id) {
290  for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
291       it != policy_brokers_.end(); ++it) {
292    if (it->second->account_id() == account_id) {
293      DCHECK(!it->second->extension_loader()->IsCacheRunning());
294      it->second->extension_loader()->StartCache(extension_cache_task_runner_);
295      return true;
296    }
297  }
298  return false;
299}
300
301void DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted() {
302  DCHECK_EQ(IN_PROGRESS, orphan_cache_deletion_state_);
303
304  orphan_cache_deletion_state_ = DONE;
305  StartExtensionCachesIfPossible();
306}
307
308void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown(
309    const std::string& account_id) {
310  DCHECK_NE(NOT_STARTED, orphan_cache_deletion_state_);
311  DCHECK(IsExtensionCacheDirectoryBusy(account_id));
312
313  // The account with |account_id| was deleted and the broker for it has shut
314  // down completely.
315
316  if (StartExtensionCacheForAccountIfPresent(account_id)) {
317    // If another account with the same ID was created in the meantime, its
318    // extension cache is started, reusing the cache directory. The directory no
319    // longer needs to be marked as busy in this case.
320    busy_extension_cache_directories_.erase(account_id);
321    return;
322  }
323
324  // If no account with |account_id| exists anymore, the cache directory should
325  // be removed. The directory must stay marked as busy while the removal is in
326  // progress.
327  extension_cache_task_runner_->PostTaskAndReply(
328      FROM_HERE,
329      base::Bind(&DeleteObsoleteExtensionCache, account_id),
330      base::Bind(&DeviceLocalAccountPolicyService::
331                     OnObsoleteExtensionCacheDeleted,
332                 weak_factory_.GetWeakPtr(),
333                 account_id));
334}
335
336void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted(
337    const std::string& account_id) {
338  DCHECK_EQ(DONE, orphan_cache_deletion_state_);
339  DCHECK(IsExtensionCacheDirectoryBusy(account_id));
340
341  // The cache directory for |account_id| has been deleted. The directory no
342  // longer needs to be marked as busy.
343  busy_extension_cache_directories_.erase(account_id);
344
345  // If another account with the same ID was created in the meantime, start its
346  // extension cache, creating a new cache directory.
347  StartExtensionCacheForAccountIfPresent(account_id);
348}
349
350void DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending() {
351  // Avoid unnecessary calls to UpdateAccountList(): If an earlier call is still
352  // pending (because the |cros_settings_| are not trusted yet), the updated
353  // account list will be processed by that call when it eventually runs.
354  if (!waiting_for_cros_settings_)
355    UpdateAccountList();
356}
357
358void DeviceLocalAccountPolicyService::UpdateAccountList() {
359  chromeos::CrosSettingsProvider::TrustedStatus status =
360      cros_settings_->PrepareTrustedValues(
361          base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList,
362                     weak_factory_.GetWeakPtr()));
363  switch (status) {
364    case chromeos::CrosSettingsProvider::TRUSTED:
365      waiting_for_cros_settings_ = false;
366      break;
367    case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
368      waiting_for_cros_settings_ = true;
369      return;
370    case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
371      waiting_for_cros_settings_ = false;
372      return;
373  }
374
375  // Update |policy_brokers_|, keeping existing entries.
376  PolicyBrokerMap old_policy_brokers;
377  policy_brokers_.swap(old_policy_brokers);
378  std::set<std::string> subdirectories_to_keep;
379  const std::vector<DeviceLocalAccount> device_local_accounts =
380      GetDeviceLocalAccounts(cros_settings_);
381  for (std::vector<DeviceLocalAccount>::const_iterator it =
382           device_local_accounts.begin();
383       it != device_local_accounts.end(); ++it) {
384    PolicyBrokerMap::iterator broker_it = old_policy_brokers.find(it->user_id);
385
386    scoped_ptr<DeviceLocalAccountPolicyBroker> broker;
387    bool broker_initialized = false;
388    if (broker_it != old_policy_brokers.end()) {
389      // Reuse the existing broker if present.
390      broker.reset(broker_it->second);
391      old_policy_brokers.erase(broker_it);
392      broker_initialized = true;
393    } else {
394      scoped_ptr<DeviceLocalAccountPolicyStore> store(
395          new DeviceLocalAccountPolicyStore(it->account_id,
396                                            session_manager_client_,
397                                            device_settings_service_,
398                                            store_background_task_runner_));
399      store->AddObserver(this);
400      scoped_refptr<DeviceLocalAccountExternalDataManager>
401          external_data_manager =
402              external_data_service_->GetExternalDataManager(it->account_id,
403                                                             store.get());
404      broker.reset(new DeviceLocalAccountPolicyBroker(
405          *it,
406          store.Pass(),
407          external_data_manager,
408          base::MessageLoopProxy::current()));
409    }
410
411    // Fire up the cloud connection for fetching policy for the account from
412    // the cloud if this is an enterprise-managed device.
413    broker->ConnectIfPossible(device_settings_service_,
414                              device_management_service_,
415                              request_context_);
416
417    policy_brokers_[it->user_id] = broker.release();
418    if (!broker_initialized) {
419      // The broker must be initialized after it has been added to
420      // |policy_brokers_|.
421      policy_brokers_[it->user_id]->Initialize();
422    }
423
424    if (orphan_cache_deletion_state_ == NOT_STARTED) {
425      subdirectories_to_keep.insert(
426          GetCacheSubdirectoryForAccountID(it->account_id));
427    }
428  }
429
430  std::set<std::string> obsolete_account_ids;
431  for (PolicyBrokerMap::const_iterator it = old_policy_brokers.begin();
432       it != old_policy_brokers.end(); ++it) {
433    obsolete_account_ids.insert(it->second->account_id());
434  }
435
436  if (orphan_cache_deletion_state_ == NOT_STARTED) {
437    DCHECK(old_policy_brokers.empty());
438    DCHECK(busy_extension_cache_directories_.empty());
439
440    // If this method is running for the first time, no extension caches have
441    // been started yet. Take this opportunity to do a clean-up by removing
442    // orphaned cache directories not found in |subdirectories_to_keep| from the
443    // cache directory.
444    orphan_cache_deletion_state_ = IN_PROGRESS;
445    extension_cache_task_runner_->PostTaskAndReply(
446        FROM_HERE,
447        base::Bind(&DeleteOrphanedExtensionCaches, subdirectories_to_keep),
448        base::Bind(&DeviceLocalAccountPolicyService::
449                       OnOrphanedExtensionCachesDeleted,
450                   weak_factory_.GetWeakPtr()));
451
452    // Start the extension caches for all brokers. These belong to accounts in
453    // |account_ids| and are not affected by the clean-up.
454    StartExtensionCachesIfPossible();
455  } else {
456    // If this method has run before, obsolete brokers may exist. Shut down
457    // their extension caches and delete the brokers.
458    DeleteBrokers(&old_policy_brokers);
459
460    if (orphan_cache_deletion_state_ == DONE) {
461      // If the initial clean-up of orphaned cache directories has been
462      // complete, start any extension caches that are not running yet but can
463      // be started now because their cache directories are not busy.
464      StartExtensionCachesIfPossible();
465    }
466  }
467
468  FOR_EACH_OBSERVER(Observer, observers_, OnDeviceLocalAccountsChanged());
469}
470
471void DeviceLocalAccountPolicyService::DeleteBrokers(PolicyBrokerMap* map) {
472  for (PolicyBrokerMap::iterator it = map->begin(); it != map->end(); ++it) {
473    it->second->core()->store()->RemoveObserver(this);
474    scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader>
475        extension_loader = it->second->extension_loader();
476    if (extension_loader->IsCacheRunning()) {
477      DCHECK(!IsExtensionCacheDirectoryBusy(it->second->account_id()));
478      busy_extension_cache_directories_.insert(it->second->account_id());
479      extension_loader->StopCache(base::Bind(
480          &DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown,
481          weak_factory_.GetWeakPtr(),
482          it->second->account_id()));
483    }
484    delete it->second;
485  }
486  map->clear();
487}
488
489DeviceLocalAccountPolicyBroker*
490    DeviceLocalAccountPolicyService::GetBrokerForStore(
491        CloudPolicyStore* store) {
492  for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
493       it != policy_brokers_.end(); ++it) {
494    if (it->second->core()->store() == store)
495      return it->second;
496  }
497  return NULL;
498}
499
500}  // namespace policy
501