1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
10 #include "base/file_util.h"
11 #include "base/files/file_enumerator.h"
12 #include "base/files/file_path.h"
13 #include "base/logging.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/path_service.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chromeos/policy/device_local_account.h"
21 #include "chrome/browser/chromeos/policy/device_local_account_external_data_service.h"
22 #include "chrome/browser/chromeos/policy/device_local_account_policy_store.h"
23 #include "chrome/browser/chromeos/settings/device_settings_service.h"
24 #include "chromeos/chromeos_paths.h"
25 #include "chromeos/dbus/session_manager_client.h"
26 #include "chromeos/settings/cros_settings_names.h"
27 #include "chromeos/settings/cros_settings_provider.h"
28 #include "components/policy/core/common/cloud/cloud_policy_client.h"
29 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
30 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
31 #include "components/policy/core/common/cloud/device_management_service.h"
32 #include "components/policy/core/common/cloud/system_policy_request_context.h"
33 #include "content/public/common/content_client.h"
34 #include "net/url_request/url_request_context_getter.h"
35 #include "policy/policy_constants.h"
36 #include "policy/proto/device_management_backend.pb.h"
39 namespace em = enterprise_management;
45 // Creates and initializes a cloud policy client. Returns NULL if the device
46 // doesn't have credentials in device settings (i.e. is not
47 // enterprise-enrolled).
48 scoped_ptr<CloudPolicyClient> CreateClient(
49 chromeos::DeviceSettingsService* device_settings_service,
50 DeviceManagementService* device_management_service,
51 scoped_refptr<net::URLRequestContextGetter> system_request_context) {
52 const em::PolicyData* policy_data = device_settings_service->policy_data();
54 !policy_data->has_request_token() ||
55 !policy_data->has_device_id() ||
56 !device_management_service) {
57 return scoped_ptr<CloudPolicyClient>();
60 scoped_refptr<net::URLRequestContextGetter> request_context =
61 new SystemPolicyRequestContext(
62 system_request_context,
63 content::GetUserAgent(GURL(
64 device_management_service->GetServerUrl())));
66 scoped_ptr<CloudPolicyClient> client(
67 new CloudPolicyClient(std::string(), std::string(),
68 kPolicyVerificationKeyHash,
69 USER_AFFILIATION_MANAGED,
70 NULL, device_management_service, request_context));
71 client->SetupRegistration(policy_data->request_token(),
72 policy_data->device_id());
76 // Get the subdirectory of the cache directory in which force-installed
77 // extensions are cached for |account_id|.
78 std::string GetCacheSubdirectoryForAccountID(const std::string& account_id) {
79 return base::HexEncode(account_id.c_str(), account_id.size());
82 // Cleans up the cache directory by removing subdirectories that are not found
83 // in |subdirectories_to_keep|. Only caches whose cache directory is found in
84 // |subdirectories_to_keep| may be running while the clean-up is in progress.
85 void DeleteOrphanedExtensionCaches(
86 const std::set<std::string>& subdirectories_to_keep) {
87 base::FilePath cache_root_dir;
88 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
90 base::FileEnumerator enumerator(cache_root_dir,
92 base::FileEnumerator::DIRECTORIES);
93 for (base::FilePath path = enumerator.Next(); !path.empty();
94 path = enumerator.Next()) {
95 const std::string subdirectory(path.BaseName().MaybeAsASCII());
96 if (subdirectories_to_keep.find(subdirectory) ==
97 subdirectories_to_keep.end()) {
98 base::DeleteFile(path, true);
103 // Removes the subdirectory belonging to |account_id_to_delete| from the cache
104 // directory. No cache belonging to |account_id_to_delete| may be running while
105 // the removal is in progress.
106 void DeleteObsoleteExtensionCache(const std::string& account_id_to_delete) {
107 base::FilePath cache_root_dir;
108 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
110 const base::FilePath path = cache_root_dir
111 .Append(GetCacheSubdirectoryForAccountID(account_id_to_delete));
112 if (base::DirectoryExists(path))
113 base::DeleteFile(path, true);
118 DeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker(
119 const DeviceLocalAccount& account,
120 scoped_ptr<DeviceLocalAccountPolicyStore> store,
121 scoped_refptr<DeviceLocalAccountExternalDataManager> external_data_manager,
122 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
123 : account_id_(account.account_id),
124 user_id_(account.user_id),
125 store_(store.Pass()),
126 external_data_manager_(external_data_manager),
127 core_(PolicyNamespaceKey(dm_protocol::kChromePublicAccountPolicyType,
128 store_->account_id()),
131 base::FilePath cache_root_dir;
132 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
134 extension_loader_ = new chromeos::DeviceLocalAccountExternalPolicyLoader(
136 cache_root_dir.Append(
137 GetCacheSubdirectoryForAccountID(account.account_id)));
140 DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {
141 external_data_manager_->SetPolicyStore(NULL);
142 external_data_manager_->Disconnect();
145 void DeviceLocalAccountPolicyBroker::Initialize() {
149 void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
150 chromeos::DeviceSettingsService* device_settings_service,
151 DeviceManagementService* device_management_service,
152 scoped_refptr<net::URLRequestContextGetter> request_context) {
156 scoped_ptr<CloudPolicyClient> client(CreateClient(device_settings_service,
157 device_management_service,
162 core_.Connect(client.Pass());
163 external_data_manager_->Connect(request_context);
164 core_.StartRefreshScheduler();
165 UpdateRefreshDelay();
168 void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() {
169 if (core_.refresh_scheduler()) {
170 const base::Value* policy_value =
171 store_->policy_map().GetValue(key::kPolicyRefreshRate);
173 if (policy_value && policy_value->GetAsInteger(&delay))
174 core_.refresh_scheduler()->SetRefreshDelay(delay);
178 std::string DeviceLocalAccountPolicyBroker::GetDisplayName() const {
179 std::string display_name;
180 const base::Value* display_name_value =
181 store_->policy_map().GetValue(policy::key::kUserDisplayName);
182 if (display_name_value)
183 display_name_value->GetAsString(&display_name);
187 DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
188 chromeos::SessionManagerClient* session_manager_client,
189 chromeos::DeviceSettingsService* device_settings_service,
190 chromeos::CrosSettings* cros_settings,
191 scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
192 scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner,
193 scoped_refptr<base::SequencedTaskRunner>
194 external_data_service_backend_task_runner,
195 scoped_refptr<base::SequencedTaskRunner> io_task_runner,
196 scoped_refptr<net::URLRequestContextGetter> request_context)
197 : session_manager_client_(session_manager_client),
198 device_settings_service_(device_settings_service),
199 cros_settings_(cros_settings),
200 device_management_service_(NULL),
201 waiting_for_cros_settings_(false),
202 orphan_cache_deletion_state_(NOT_STARTED),
203 store_background_task_runner_(store_background_task_runner),
204 extension_cache_task_runner_(extension_cache_task_runner),
205 request_context_(request_context),
206 local_accounts_subscription_(cros_settings_->AddSettingsObserver(
207 chromeos::kAccountsPrefDeviceLocalAccounts,
208 base::Bind(&DeviceLocalAccountPolicyService::
209 UpdateAccountListIfNonePending,
210 base::Unretained(this)))),
211 weak_factory_(this) {
212 external_data_service_.reset(new DeviceLocalAccountExternalDataService(
214 external_data_service_backend_task_runner,
219 DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() {
220 DCHECK(!request_context_);
221 DCHECK(policy_brokers_.empty());
224 void DeviceLocalAccountPolicyService::Shutdown() {
225 device_management_service_ = NULL;
226 request_context_ = NULL;
227 DeleteBrokers(&policy_brokers_);
230 void DeviceLocalAccountPolicyService::Connect(
231 DeviceManagementService* device_management_service) {
232 DCHECK(!device_management_service_);
233 device_management_service_ = device_management_service;
235 // Connect the brokers.
236 for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
237 it != policy_brokers_.end(); ++it) {
238 it->second->ConnectIfPossible(device_settings_service_,
239 device_management_service_,
244 DeviceLocalAccountPolicyBroker*
245 DeviceLocalAccountPolicyService::GetBrokerForUser(
246 const std::string& user_id) {
247 PolicyBrokerMap::iterator entry = policy_brokers_.find(user_id);
248 if (entry == policy_brokers_.end())
251 return entry->second;
254 bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser(
255 const std::string& user_id) {
256 DeviceLocalAccountPolicyBroker* broker = GetBrokerForUser(user_id);
257 return broker && broker->core()->store()->is_managed();
260 void DeviceLocalAccountPolicyService::AddObserver(Observer* observer) {
261 observers_.AddObserver(observer);
264 void DeviceLocalAccountPolicyService::RemoveObserver(Observer* observer) {
265 observers_.RemoveObserver(observer);
268 void DeviceLocalAccountPolicyService::OnStoreLoaded(CloudPolicyStore* store) {
269 DeviceLocalAccountPolicyBroker* broker = GetBrokerForStore(store);
273 broker->UpdateRefreshDelay();
274 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(broker->user_id()));
277 void DeviceLocalAccountPolicyService::OnStoreError(CloudPolicyStore* store) {
278 DeviceLocalAccountPolicyBroker* broker = GetBrokerForStore(store);
282 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(broker->user_id()));
285 bool DeviceLocalAccountPolicyService::IsExtensionCacheDirectoryBusy(
286 const std::string& account_id) {
287 return busy_extension_cache_directories_.find(account_id) !=
288 busy_extension_cache_directories_.end();
291 void DeviceLocalAccountPolicyService::StartExtensionCachesIfPossible() {
292 for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
293 it != policy_brokers_.end(); ++it) {
294 if (!it->second->extension_loader()->IsCacheRunning() &&
295 !IsExtensionCacheDirectoryBusy(it->second->account_id())) {
296 it->second->extension_loader()->StartCache(extension_cache_task_runner_);
301 bool DeviceLocalAccountPolicyService::StartExtensionCacheForAccountIfPresent(
302 const std::string& account_id) {
303 for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
304 it != policy_brokers_.end(); ++it) {
305 if (it->second->account_id() == account_id) {
306 DCHECK(!it->second->extension_loader()->IsCacheRunning());
307 it->second->extension_loader()->StartCache(extension_cache_task_runner_);
314 void DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted() {
315 DCHECK_EQ(IN_PROGRESS, orphan_cache_deletion_state_);
317 orphan_cache_deletion_state_ = DONE;
318 StartExtensionCachesIfPossible();
321 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown(
322 const std::string& account_id) {
323 DCHECK_NE(NOT_STARTED, orphan_cache_deletion_state_);
324 DCHECK(IsExtensionCacheDirectoryBusy(account_id));
326 // The account with |account_id| was deleted and the broker for it has shut
329 if (StartExtensionCacheForAccountIfPresent(account_id)) {
330 // If another account with the same ID was created in the meantime, its
331 // extension cache is started, reusing the cache directory. The directory no
332 // longer needs to be marked as busy in this case.
333 busy_extension_cache_directories_.erase(account_id);
337 // If no account with |account_id| exists anymore, the cache directory should
338 // be removed. The directory must stay marked as busy while the removal is in
340 extension_cache_task_runner_->PostTaskAndReply(
342 base::Bind(&DeleteObsoleteExtensionCache, account_id),
343 base::Bind(&DeviceLocalAccountPolicyService::
344 OnObsoleteExtensionCacheDeleted,
345 weak_factory_.GetWeakPtr(),
349 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted(
350 const std::string& account_id) {
351 DCHECK_EQ(DONE, orphan_cache_deletion_state_);
352 DCHECK(IsExtensionCacheDirectoryBusy(account_id));
354 // The cache directory for |account_id| has been deleted. The directory no
355 // longer needs to be marked as busy.
356 busy_extension_cache_directories_.erase(account_id);
358 // If another account with the same ID was created in the meantime, start its
359 // extension cache, creating a new cache directory.
360 StartExtensionCacheForAccountIfPresent(account_id);
363 void DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending() {
364 // Avoid unnecessary calls to UpdateAccountList(): If an earlier call is still
365 // pending (because the |cros_settings_| are not trusted yet), the updated
366 // account list will be processed by that call when it eventually runs.
367 if (!waiting_for_cros_settings_)
371 void DeviceLocalAccountPolicyService::UpdateAccountList() {
372 chromeos::CrosSettingsProvider::TrustedStatus status =
373 cros_settings_->PrepareTrustedValues(
374 base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList,
375 weak_factory_.GetWeakPtr()));
377 case chromeos::CrosSettingsProvider::TRUSTED:
378 waiting_for_cros_settings_ = false;
380 case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
381 waiting_for_cros_settings_ = true;
383 case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
384 waiting_for_cros_settings_ = false;
388 // Update |policy_brokers_|, keeping existing entries.
389 PolicyBrokerMap old_policy_brokers;
390 policy_brokers_.swap(old_policy_brokers);
391 std::set<std::string> subdirectories_to_keep;
392 const std::vector<DeviceLocalAccount> device_local_accounts =
393 GetDeviceLocalAccounts(cros_settings_);
394 for (std::vector<DeviceLocalAccount>::const_iterator it =
395 device_local_accounts.begin();
396 it != device_local_accounts.end(); ++it) {
397 PolicyBrokerMap::iterator broker_it = old_policy_brokers.find(it->user_id);
399 scoped_ptr<DeviceLocalAccountPolicyBroker> broker;
400 bool broker_initialized = false;
401 if (broker_it != old_policy_brokers.end()) {
402 // Reuse the existing broker if present.
403 broker.reset(broker_it->second);
404 old_policy_brokers.erase(broker_it);
405 broker_initialized = true;
407 scoped_ptr<DeviceLocalAccountPolicyStore> store(
408 new DeviceLocalAccountPolicyStore(it->account_id,
409 session_manager_client_,
410 device_settings_service_,
411 store_background_task_runner_));
412 store->AddObserver(this);
413 scoped_refptr<DeviceLocalAccountExternalDataManager>
414 external_data_manager =
415 external_data_service_->GetExternalDataManager(it->account_id,
417 broker.reset(new DeviceLocalAccountPolicyBroker(
420 external_data_manager,
421 base::MessageLoopProxy::current()));
424 // Fire up the cloud connection for fetching policy for the account from
425 // the cloud if this is an enterprise-managed device.
426 broker->ConnectIfPossible(device_settings_service_,
427 device_management_service_,
430 policy_brokers_[it->user_id] = broker.release();
431 if (!broker_initialized) {
432 // The broker must be initialized after it has been added to
433 // |policy_brokers_|.
434 policy_brokers_[it->user_id]->Initialize();
437 if (orphan_cache_deletion_state_ == NOT_STARTED) {
438 subdirectories_to_keep.insert(
439 GetCacheSubdirectoryForAccountID(it->account_id));
443 std::set<std::string> obsolete_account_ids;
444 for (PolicyBrokerMap::const_iterator it = old_policy_brokers.begin();
445 it != old_policy_brokers.end(); ++it) {
446 obsolete_account_ids.insert(it->second->account_id());
449 if (orphan_cache_deletion_state_ == NOT_STARTED) {
450 DCHECK(old_policy_brokers.empty());
451 DCHECK(busy_extension_cache_directories_.empty());
453 // If this method is running for the first time, no extension caches have
454 // been started yet. Take this opportunity to do a clean-up by removing
455 // orphaned cache directories not found in |subdirectories_to_keep| from the
457 orphan_cache_deletion_state_ = IN_PROGRESS;
458 extension_cache_task_runner_->PostTaskAndReply(
460 base::Bind(&DeleteOrphanedExtensionCaches, subdirectories_to_keep),
461 base::Bind(&DeviceLocalAccountPolicyService::
462 OnOrphanedExtensionCachesDeleted,
463 weak_factory_.GetWeakPtr()));
465 // Start the extension caches for all brokers. These belong to accounts in
466 // |account_ids| and are not affected by the clean-up.
467 StartExtensionCachesIfPossible();
469 // If this method has run before, obsolete brokers may exist. Shut down
470 // their extension caches and delete the brokers.
471 DeleteBrokers(&old_policy_brokers);
473 if (orphan_cache_deletion_state_ == DONE) {
474 // If the initial clean-up of orphaned cache directories has been
475 // complete, start any extension caches that are not running yet but can
476 // be started now because their cache directories are not busy.
477 StartExtensionCachesIfPossible();
481 FOR_EACH_OBSERVER(Observer, observers_, OnDeviceLocalAccountsChanged());
484 void DeviceLocalAccountPolicyService::DeleteBrokers(PolicyBrokerMap* map) {
485 for (PolicyBrokerMap::iterator it = map->begin(); it != map->end(); ++it) {
486 it->second->core()->store()->RemoveObserver(this);
487 scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader>
488 extension_loader = it->second->extension_loader();
489 if (extension_loader->IsCacheRunning()) {
490 DCHECK(!IsExtensionCacheDirectoryBusy(it->second->account_id()));
491 busy_extension_cache_directories_.insert(it->second->account_id());
492 extension_loader->StopCache(base::Bind(
493 &DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown,
494 weak_factory_.GetWeakPtr(),
495 it->second->account_id()));
502 DeviceLocalAccountPolicyBroker*
503 DeviceLocalAccountPolicyService::GetBrokerForStore(
504 CloudPolicyStore* store) {
505 for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
506 it != policy_brokers_.end(); ++it) {
507 if (it->second->core()->store() == store)
513 } // namespace policy