Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / chromeos / policy / device_local_account_policy_service.cc
blobd513998019595067feb51709d18547d6fd856f46
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"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/command_line.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_util.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/path_service.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/thread_task_runner_handle.h"
21 #include "base/thread_task_runner_handle.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h"
24 #include "chrome/browser/chromeos/policy/device_local_account.h"
25 #include "chrome/browser/chromeos/policy/device_local_account_external_data_service.h"
26 #include "chrome/browser/chromeos/policy/device_local_account_policy_store.h"
27 #include "chrome/browser/chromeos/settings/device_settings_service.h"
28 #include "chrome/common/chrome_content_client.h"
29 #include "chromeos/chromeos_paths.h"
30 #include "chromeos/dbus/session_manager_client.h"
31 #include "chromeos/settings/cros_settings_names.h"
32 #include "chromeos/settings/cros_settings_provider.h"
33 #include "components/policy/core/browser/browser_policy_connector.h"
34 #include "components/policy/core/common/cloud/cloud_policy_client.h"
35 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
36 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
37 #include "components/policy/core/common/cloud/device_management_service.h"
38 #include "components/policy/core/common/cloud/resource_cache.h"
39 #include "components/policy/core/common/cloud/system_policy_request_context.h"
40 #include "components/policy/core/common/policy_namespace.h"
41 #include "components/policy/core/common/policy_switches.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "net/url_request/url_request_context_getter.h"
44 #include "policy/policy_constants.h"
45 #include "policy/proto/device_management_backend.pb.h"
46 #include "url/gurl.h"
48 namespace em = enterprise_management;
50 namespace policy {
52 namespace {
54 // Creates and initializes a cloud policy client. Returns nullptr if the device
55 // is not enterprise-enrolled.
56 scoped_ptr<CloudPolicyClient> CreateClient(
57 chromeos::DeviceSettingsService* device_settings_service,
58 DeviceManagementService* device_management_service,
59 scoped_refptr<net::URLRequestContextGetter> system_request_context) {
60 const em::PolicyData* policy_data = device_settings_service->policy_data();
61 if (!policy_data ||
62 GetManagementMode(*policy_data) != MANAGEMENT_MODE_ENTERPRISE_MANAGED ||
63 !device_management_service) {
64 return scoped_ptr<CloudPolicyClient>();
67 scoped_refptr<net::URLRequestContextGetter> request_context =
68 new SystemPolicyRequestContext(
69 system_request_context, GetUserAgent());
71 scoped_ptr<CloudPolicyClient> client(
72 new CloudPolicyClient(std::string(), std::string(),
73 kPolicyVerificationKeyHash,
74 device_management_service, request_context));
75 client->SetupRegistration(policy_data->request_token(),
76 policy_data->device_id());
77 return client.Pass();
80 // Get the subdirectory of the force-installed extension cache and the component
81 // policy cache used for |account_id|.
82 std::string GetCacheSubdirectoryForAccountID(const std::string& account_id) {
83 return base::HexEncode(account_id.c_str(), account_id.size());
86 // Cleans up the cache directory by removing subdirectories that are not found
87 // in |subdirectories_to_keep|. Only caches whose cache directory is found in
88 // |subdirectories_to_keep| may be running while the clean-up is in progress.
89 void DeleteOrphanedCaches(
90 const base::FilePath& cache_root_dir,
91 const std::set<std::string>& subdirectories_to_keep) {
92 base::FileEnumerator enumerator(cache_root_dir,
93 false,
94 base::FileEnumerator::DIRECTORIES);
95 for (base::FilePath path = enumerator.Next(); !path.empty();
96 path = enumerator.Next()) {
97 const std::string subdirectory(path.BaseName().MaybeAsASCII());
98 if (!ContainsKey(subdirectories_to_keep, subdirectory))
99 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,
109 &cache_root_dir));
110 const base::FilePath path = cache_root_dir.Append(
111 GetCacheSubdirectoryForAccountID(account_id_to_delete));
112 if (base::DirectoryExists(path))
113 base::DeleteFile(path, true);
116 } // namespace
118 DeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker(
119 const DeviceLocalAccount& account,
120 const base::FilePath& component_policy_cache_path,
121 scoped_ptr<DeviceLocalAccountPolicyStore> store,
122 scoped_refptr<DeviceLocalAccountExternalDataManager> external_data_manager,
123 const base::Closure& policy_update_callback,
124 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
125 AffiliatedInvalidationServiceProvider* invalidation_service_provider)
126 : invalidation_service_provider_(invalidation_service_provider),
127 account_id_(account.account_id),
128 user_id_(account.user_id),
129 component_policy_cache_path_(component_policy_cache_path),
130 store_(store.Pass()),
131 extension_tracker_(account, store_.get(), &schema_registry_),
132 external_data_manager_(external_data_manager),
133 core_(dm_protocol::kChromePublicAccountPolicyType,
134 store_->account_id(),
135 store_.get(),
136 task_runner),
137 policy_update_callback_(policy_update_callback) {
138 base::FilePath cache_root_dir;
139 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
140 &cache_root_dir));
141 extension_loader_ = new chromeos::DeviceLocalAccountExternalPolicyLoader(
142 store_.get(),
143 cache_root_dir.Append(
144 GetCacheSubdirectoryForAccountID(account.account_id)));
145 store_->AddObserver(this);
147 // Unblock the |schema_registry_| so that the |component_policy_service_|
148 // starts using it.
149 schema_registry_.RegisterComponent(
150 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()),
151 g_browser_process->browser_policy_connector()->GetChromeSchema());
152 schema_registry_.SetReady(POLICY_DOMAIN_CHROME);
153 schema_registry_.SetReady(POLICY_DOMAIN_EXTENSIONS);
156 DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {
157 store_->RemoveObserver(this);
158 external_data_manager_->SetPolicyStore(nullptr);
159 external_data_manager_->Disconnect();
162 void DeviceLocalAccountPolicyBroker::Initialize() {
163 store_->Load();
166 bool DeviceLocalAccountPolicyBroker::HasInvalidatorForTest() const {
167 return invalidator_;
170 void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
171 chromeos::DeviceSettingsService* device_settings_service,
172 DeviceManagementService* device_management_service,
173 scoped_refptr<net::URLRequestContextGetter> request_context) {
174 if (core_.client())
175 return;
177 scoped_ptr<CloudPolicyClient> client(CreateClient(device_settings_service,
178 device_management_service,
179 request_context));
180 if (!client)
181 return;
183 CreateComponentCloudPolicyService(request_context, client.get());
184 core_.Connect(client.Pass());
185 external_data_manager_->Connect(request_context);
186 core_.StartRefreshScheduler();
187 UpdateRefreshDelay();
188 invalidator_.reset(new AffiliatedCloudPolicyInvalidator(
189 em::DeviceRegisterRequest::DEVICE,
190 &core_,
191 invalidation_service_provider_));
194 void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() {
195 if (core_.refresh_scheduler()) {
196 const base::Value* policy_value =
197 store_->policy_map().GetValue(key::kPolicyRefreshRate);
198 int delay = 0;
199 if (policy_value && policy_value->GetAsInteger(&delay))
200 core_.refresh_scheduler()->SetRefreshDelay(delay);
204 std::string DeviceLocalAccountPolicyBroker::GetDisplayName() const {
205 std::string display_name;
206 const base::Value* display_name_value =
207 store_->policy_map().GetValue(policy::key::kUserDisplayName);
208 if (display_name_value)
209 display_name_value->GetAsString(&display_name);
210 return display_name;
213 void DeviceLocalAccountPolicyBroker::OnStoreLoaded(CloudPolicyStore* store) {
214 UpdateRefreshDelay();
215 policy_update_callback_.Run();
218 void DeviceLocalAccountPolicyBroker::OnStoreError(CloudPolicyStore* store) {
219 policy_update_callback_.Run();
222 void DeviceLocalAccountPolicyBroker::OnComponentCloudPolicyUpdated() {
223 policy_update_callback_.Run();
226 void DeviceLocalAccountPolicyBroker::CreateComponentCloudPolicyService(
227 const scoped_refptr<net::URLRequestContextGetter>& request_context,
228 CloudPolicyClient* client) {
229 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
230 switches::kDisableComponentCloudPolicy)) {
231 // Disabled via the command line.
232 return;
235 scoped_ptr<ResourceCache> resource_cache(
236 new ResourceCache(component_policy_cache_path_,
237 content::BrowserThread::GetMessageLoopProxyForThread(
238 content::BrowserThread::FILE)));
240 component_policy_service_.reset(new ComponentCloudPolicyService(
241 this,
242 &schema_registry_,
243 core(),
244 client,
245 resource_cache.Pass(),
246 request_context,
247 content::BrowserThread::GetMessageLoopProxyForThread(
248 content::BrowserThread::FILE),
249 content::BrowserThread::GetMessageLoopProxyForThread(
250 content::BrowserThread::IO)));
253 DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
254 chromeos::SessionManagerClient* session_manager_client,
255 chromeos::DeviceSettingsService* device_settings_service,
256 chromeos::CrosSettings* cros_settings,
257 AffiliatedInvalidationServiceProvider* invalidation_service_provider,
258 scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
259 scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner,
260 scoped_refptr<base::SequencedTaskRunner>
261 external_data_service_backend_task_runner,
262 scoped_refptr<base::SequencedTaskRunner> io_task_runner,
263 scoped_refptr<net::URLRequestContextGetter> request_context)
264 : session_manager_client_(session_manager_client),
265 device_settings_service_(device_settings_service),
266 cros_settings_(cros_settings),
267 invalidation_service_provider_(invalidation_service_provider),
268 device_management_service_(nullptr),
269 waiting_for_cros_settings_(false),
270 orphan_extension_cache_deletion_state_(NOT_STARTED),
271 store_background_task_runner_(store_background_task_runner),
272 extension_cache_task_runner_(extension_cache_task_runner),
273 request_context_(request_context),
274 local_accounts_subscription_(cros_settings_->AddSettingsObserver(
275 chromeos::kAccountsPrefDeviceLocalAccounts,
276 base::Bind(&DeviceLocalAccountPolicyService::
277 UpdateAccountListIfNonePending,
278 base::Unretained(this)))),
279 weak_factory_(this) {
280 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_COMPONENT_POLICY,
281 &component_policy_cache_root_));
282 external_data_service_.reset(new DeviceLocalAccountExternalDataService(
283 this,
284 external_data_service_backend_task_runner,
285 io_task_runner));
286 UpdateAccountList();
289 DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() {
290 DCHECK(!request_context_.get());
291 DCHECK(policy_brokers_.empty());
294 void DeviceLocalAccountPolicyService::Shutdown() {
295 device_management_service_ = nullptr;
296 request_context_ = nullptr;
297 DeleteBrokers(&policy_brokers_);
300 void DeviceLocalAccountPolicyService::Connect(
301 DeviceManagementService* device_management_service) {
302 DCHECK(!device_management_service_);
303 device_management_service_ = device_management_service;
305 // Connect the brokers.
306 for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
307 it != policy_brokers_.end(); ++it) {
308 it->second->ConnectIfPossible(device_settings_service_,
309 device_management_service_,
310 request_context_);
314 DeviceLocalAccountPolicyBroker*
315 DeviceLocalAccountPolicyService::GetBrokerForUser(
316 const std::string& user_id) {
317 PolicyBrokerMap::iterator entry = policy_brokers_.find(user_id);
318 if (entry == policy_brokers_.end())
319 return nullptr;
321 return entry->second;
324 bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser(
325 const std::string& user_id) {
326 DeviceLocalAccountPolicyBroker* broker = GetBrokerForUser(user_id);
327 return broker && broker->core()->store()->is_managed();
330 void DeviceLocalAccountPolicyService::AddObserver(Observer* observer) {
331 observers_.AddObserver(observer);
334 void DeviceLocalAccountPolicyService::RemoveObserver(Observer* observer) {
335 observers_.RemoveObserver(observer);
338 bool DeviceLocalAccountPolicyService::IsExtensionCacheDirectoryBusy(
339 const std::string& account_id) {
340 return busy_extension_cache_directories_.find(account_id) !=
341 busy_extension_cache_directories_.end();
344 void DeviceLocalAccountPolicyService::StartExtensionCachesIfPossible() {
345 for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
346 it != policy_brokers_.end(); ++it) {
347 if (!it->second->extension_loader()->IsCacheRunning() &&
348 !IsExtensionCacheDirectoryBusy(it->second->account_id())) {
349 it->second->extension_loader()->StartCache(extension_cache_task_runner_);
354 bool DeviceLocalAccountPolicyService::StartExtensionCacheForAccountIfPresent(
355 const std::string& account_id) {
356 for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
357 it != policy_brokers_.end(); ++it) {
358 if (it->second->account_id() == account_id) {
359 DCHECK(!it->second->extension_loader()->IsCacheRunning());
360 it->second->extension_loader()->StartCache(extension_cache_task_runner_);
361 return true;
364 return false;
367 void DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted() {
368 DCHECK_EQ(IN_PROGRESS, orphan_extension_cache_deletion_state_);
370 orphan_extension_cache_deletion_state_ = DONE;
371 StartExtensionCachesIfPossible();
374 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown(
375 const std::string& account_id) {
376 DCHECK_NE(NOT_STARTED, orphan_extension_cache_deletion_state_);
377 DCHECK(IsExtensionCacheDirectoryBusy(account_id));
379 // The account with |account_id| was deleted and the broker for it has shut
380 // down completely.
382 if (StartExtensionCacheForAccountIfPresent(account_id)) {
383 // If another account with the same ID was created in the meantime, its
384 // extension cache is started, reusing the cache directory. The directory no
385 // longer needs to be marked as busy in this case.
386 busy_extension_cache_directories_.erase(account_id);
387 return;
390 // If no account with |account_id| exists anymore, the cache directory should
391 // be removed. The directory must stay marked as busy while the removal is in
392 // progress.
393 extension_cache_task_runner_->PostTaskAndReply(
394 FROM_HERE,
395 base::Bind(&DeleteObsoleteExtensionCache, account_id),
396 base::Bind(&DeviceLocalAccountPolicyService::
397 OnObsoleteExtensionCacheDeleted,
398 weak_factory_.GetWeakPtr(),
399 account_id));
402 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted(
403 const std::string& account_id) {
404 DCHECK_EQ(DONE, orphan_extension_cache_deletion_state_);
405 DCHECK(IsExtensionCacheDirectoryBusy(account_id));
407 // The cache directory for |account_id| has been deleted. The directory no
408 // longer needs to be marked as busy.
409 busy_extension_cache_directories_.erase(account_id);
411 // If another account with the same ID was created in the meantime, start its
412 // extension cache, creating a new cache directory.
413 StartExtensionCacheForAccountIfPresent(account_id);
416 void DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending() {
417 // Avoid unnecessary calls to UpdateAccountList(): If an earlier call is still
418 // pending (because the |cros_settings_| are not trusted yet), the updated
419 // account list will be processed by that call when it eventually runs.
420 if (!waiting_for_cros_settings_)
421 UpdateAccountList();
424 void DeviceLocalAccountPolicyService::UpdateAccountList() {
425 chromeos::CrosSettingsProvider::TrustedStatus status =
426 cros_settings_->PrepareTrustedValues(
427 base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList,
428 weak_factory_.GetWeakPtr()));
429 switch (status) {
430 case chromeos::CrosSettingsProvider::TRUSTED:
431 waiting_for_cros_settings_ = false;
432 break;
433 case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
434 waiting_for_cros_settings_ = true;
435 return;
436 case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
437 waiting_for_cros_settings_ = false;
438 return;
441 // Update |policy_brokers_|, keeping existing entries.
442 PolicyBrokerMap old_policy_brokers;
443 policy_brokers_.swap(old_policy_brokers);
444 std::set<std::string> subdirectories_to_keep;
445 const std::vector<DeviceLocalAccount> device_local_accounts =
446 GetDeviceLocalAccounts(cros_settings_);
447 for (std::vector<DeviceLocalAccount>::const_iterator it =
448 device_local_accounts.begin();
449 it != device_local_accounts.end(); ++it) {
450 PolicyBrokerMap::iterator broker_it = old_policy_brokers.find(it->user_id);
452 scoped_ptr<DeviceLocalAccountPolicyBroker> broker;
453 bool broker_initialized = false;
454 if (broker_it != old_policy_brokers.end()) {
455 // Reuse the existing broker if present.
456 broker.reset(broker_it->second);
457 old_policy_brokers.erase(broker_it);
458 broker_initialized = true;
459 } else {
460 scoped_ptr<DeviceLocalAccountPolicyStore> store(
461 new DeviceLocalAccountPolicyStore(it->account_id,
462 session_manager_client_,
463 device_settings_service_,
464 store_background_task_runner_));
465 scoped_refptr<DeviceLocalAccountExternalDataManager>
466 external_data_manager =
467 external_data_service_->GetExternalDataManager(it->account_id,
468 store.get());
469 broker.reset(new DeviceLocalAccountPolicyBroker(
470 *it,
471 component_policy_cache_root_.Append(
472 GetCacheSubdirectoryForAccountID(it->account_id)),
473 store.Pass(),
474 external_data_manager,
475 base::Bind(&DeviceLocalAccountPolicyService::NotifyPolicyUpdated,
476 base::Unretained(this),
477 it->user_id),
478 base::ThreadTaskRunnerHandle::Get(),
479 invalidation_service_provider_));
482 // Fire up the cloud connection for fetching policy for the account from
483 // the cloud if this is an enterprise-managed device.
484 broker->ConnectIfPossible(device_settings_service_,
485 device_management_service_,
486 request_context_);
488 policy_brokers_[it->user_id] = broker.release();
489 if (!broker_initialized) {
490 // The broker must be initialized after it has been added to
491 // |policy_brokers_|.
492 policy_brokers_[it->user_id]->Initialize();
495 subdirectories_to_keep.insert(
496 GetCacheSubdirectoryForAccountID(it->account_id));
499 if (orphan_extension_cache_deletion_state_ == NOT_STARTED) {
500 DCHECK(old_policy_brokers.empty());
501 DCHECK(busy_extension_cache_directories_.empty());
503 // If this method is running for the first time, no extension caches have
504 // been started yet. Take this opportunity to do a clean-up by removing
505 // orphaned cache directories not found in |subdirectories_to_keep| from the
506 // cache directory.
507 orphan_extension_cache_deletion_state_ = IN_PROGRESS;
509 base::FilePath cache_root_dir;
510 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
511 &cache_root_dir));
512 extension_cache_task_runner_->PostTaskAndReply(
513 FROM_HERE,
514 base::Bind(
515 &DeleteOrphanedCaches, cache_root_dir, subdirectories_to_keep),
516 base::Bind(
517 &DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted,
518 weak_factory_.GetWeakPtr()));
520 // Start the extension caches for all brokers. These belong to accounts in
521 // |account_ids| and are not affected by the clean-up.
522 StartExtensionCachesIfPossible();
523 } else {
524 // If this method has run before, obsolete brokers may exist. Shut down
525 // their extension caches and delete the brokers.
526 DeleteBrokers(&old_policy_brokers);
528 if (orphan_extension_cache_deletion_state_ == DONE) {
529 // If the initial clean-up of orphaned cache directories has been
530 // complete, start any extension caches that are not running yet but can
531 // be started now because their cache directories are not busy.
532 StartExtensionCachesIfPossible();
536 // Purge the component policy caches of any accounts that have been removed.
537 // Do this only after any obsolete brokers have been destroyed.
538 // TODO(joaodasilva): for now this must be posted to the FILE thread,
539 // to avoid racing with the ComponentCloudPolicyStore. Use a task runner
540 // once that class supports another background thread too.
541 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
542 base::Bind(&DeleteOrphanedCaches,
543 component_policy_cache_root_,
544 subdirectories_to_keep));
546 FOR_EACH_OBSERVER(Observer, observers_, OnDeviceLocalAccountsChanged());
549 void DeviceLocalAccountPolicyService::DeleteBrokers(PolicyBrokerMap* map) {
550 for (PolicyBrokerMap::iterator it = map->begin(); it != map->end(); ++it) {
551 scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader>
552 extension_loader = it->second->extension_loader();
553 if (extension_loader->IsCacheRunning()) {
554 DCHECK(!IsExtensionCacheDirectoryBusy(it->second->account_id()));
555 busy_extension_cache_directories_.insert(it->second->account_id());
556 extension_loader->StopCache(base::Bind(
557 &DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown,
558 weak_factory_.GetWeakPtr(),
559 it->second->account_id()));
562 delete it->second;
564 map->clear();
567 DeviceLocalAccountPolicyBroker*
568 DeviceLocalAccountPolicyService::GetBrokerForStore(
569 CloudPolicyStore* store) {
570 for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
571 it != policy_brokers_.end(); ++it) {
572 if (it->second->core()->store() == store)
573 return it->second;
575 return nullptr;
578 void DeviceLocalAccountPolicyService::NotifyPolicyUpdated(
579 const std::string& user_id) {
580 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(user_id));
583 } // namespace policy