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/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/message_loop/message_loop_proxy.h"
17 #include "base/path_service.h"
18 #include "base/sequenced_task_runner.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string_number_conversions.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"
48 namespace em
= enterprise_management
;
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();
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 USER_AFFILIATION_MANAGED
,
75 device_management_service
, request_context
));
76 client
->SetupRegistration(policy_data
->request_token(),
77 policy_data
->device_id());
81 // Get the subdirectory of the force-installed extension cache and the component
82 // policy cache used for |account_id|.
83 std::string
GetCacheSubdirectoryForAccountID(const std::string
& account_id
) {
84 return base::HexEncode(account_id
.c_str(), account_id
.size());
87 // Cleans up the cache directory by removing subdirectories that are not found
88 // in |subdirectories_to_keep|. Only caches whose cache directory is found in
89 // |subdirectories_to_keep| may be running while the clean-up is in progress.
90 void DeleteOrphanedCaches(
91 const base::FilePath
& cache_root_dir
,
92 const std::set
<std::string
>& subdirectories_to_keep
) {
93 base::FileEnumerator
enumerator(cache_root_dir
,
95 base::FileEnumerator::DIRECTORIES
);
96 for (base::FilePath path
= enumerator
.Next(); !path
.empty();
97 path
= enumerator
.Next()) {
98 const std::string
subdirectory(path
.BaseName().MaybeAsASCII());
99 if (!ContainsKey(subdirectories_to_keep
, subdirectory
))
100 base::DeleteFile(path
, true);
104 // Removes the subdirectory belonging to |account_id_to_delete| from the cache
105 // directory. No cache belonging to |account_id_to_delete| may be running while
106 // the removal is in progress.
107 void DeleteObsoleteExtensionCache(const std::string
& account_id_to_delete
) {
108 base::FilePath cache_root_dir
;
109 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS
,
111 const base::FilePath path
= cache_root_dir
.Append(
112 GetCacheSubdirectoryForAccountID(account_id_to_delete
));
113 if (base::DirectoryExists(path
))
114 base::DeleteFile(path
, true);
119 DeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker(
120 const DeviceLocalAccount
& account
,
121 const base::FilePath
& component_policy_cache_path
,
122 scoped_ptr
<DeviceLocalAccountPolicyStore
> store
,
123 scoped_refptr
<DeviceLocalAccountExternalDataManager
> external_data_manager
,
124 const base::Closure
& policy_update_callback
,
125 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
,
126 AffiliatedInvalidationServiceProvider
* invalidation_service_provider
)
127 : invalidation_service_provider_(invalidation_service_provider
),
128 account_id_(account
.account_id
),
129 user_id_(account
.user_id
),
130 component_policy_cache_path_(component_policy_cache_path
),
131 store_(store
.Pass()),
132 extension_tracker_(account
, store_
.get(), &schema_registry_
),
133 external_data_manager_(external_data_manager
),
134 core_(dm_protocol::kChromePublicAccountPolicyType
,
135 store_
->account_id(),
138 policy_update_callback_(policy_update_callback
) {
139 base::FilePath cache_root_dir
;
140 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS
,
142 extension_loader_
= new chromeos::DeviceLocalAccountExternalPolicyLoader(
144 cache_root_dir
.Append(
145 GetCacheSubdirectoryForAccountID(account
.account_id
)));
146 store_
->AddObserver(this);
148 // Unblock the |schema_registry_| so that the |component_policy_service_|
150 schema_registry_
.RegisterComponent(
151 PolicyNamespace(POLICY_DOMAIN_CHROME
, std::string()),
152 g_browser_process
->browser_policy_connector()->GetChromeSchema());
153 schema_registry_
.SetReady(POLICY_DOMAIN_CHROME
);
154 schema_registry_
.SetReady(POLICY_DOMAIN_EXTENSIONS
);
157 DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {
158 store_
->RemoveObserver(this);
159 external_data_manager_
->SetPolicyStore(nullptr);
160 external_data_manager_
->Disconnect();
163 void DeviceLocalAccountPolicyBroker::Initialize() {
167 bool DeviceLocalAccountPolicyBroker::HasInvalidatorForTest() const {
171 void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
172 chromeos::DeviceSettingsService
* device_settings_service
,
173 DeviceManagementService
* device_management_service
,
174 scoped_refptr
<net::URLRequestContextGetter
> request_context
) {
178 scoped_ptr
<CloudPolicyClient
> client(CreateClient(device_settings_service
,
179 device_management_service
,
184 CreateComponentCloudPolicyService(request_context
, client
.get());
185 core_
.Connect(client
.Pass());
186 external_data_manager_
->Connect(request_context
);
187 core_
.StartRefreshScheduler();
188 UpdateRefreshDelay();
189 invalidator_
.reset(new AffiliatedCloudPolicyInvalidator(
190 em::DeviceRegisterRequest::DEVICE
,
192 invalidation_service_provider_
));
195 void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() {
196 if (core_
.refresh_scheduler()) {
197 const base::Value
* policy_value
=
198 store_
->policy_map().GetValue(key::kPolicyRefreshRate
);
200 if (policy_value
&& policy_value
->GetAsInteger(&delay
))
201 core_
.refresh_scheduler()->SetRefreshDelay(delay
);
205 std::string
DeviceLocalAccountPolicyBroker::GetDisplayName() const {
206 std::string display_name
;
207 const base::Value
* display_name_value
=
208 store_
->policy_map().GetValue(policy::key::kUserDisplayName
);
209 if (display_name_value
)
210 display_name_value
->GetAsString(&display_name
);
214 void DeviceLocalAccountPolicyBroker::OnStoreLoaded(CloudPolicyStore
* store
) {
215 UpdateRefreshDelay();
216 policy_update_callback_
.Run();
219 void DeviceLocalAccountPolicyBroker::OnStoreError(CloudPolicyStore
* store
) {
220 policy_update_callback_
.Run();
223 void DeviceLocalAccountPolicyBroker::OnComponentCloudPolicyUpdated() {
224 policy_update_callback_
.Run();
227 void DeviceLocalAccountPolicyBroker::CreateComponentCloudPolicyService(
228 const scoped_refptr
<net::URLRequestContextGetter
>& request_context
,
229 CloudPolicyClient
* client
) {
230 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
231 switches::kDisableComponentCloudPolicy
)) {
232 // Disabled via the command line.
236 scoped_ptr
<ResourceCache
> resource_cache(
237 new ResourceCache(component_policy_cache_path_
,
238 content::BrowserThread::GetMessageLoopProxyForThread(
239 content::BrowserThread::FILE)));
241 component_policy_service_
.reset(new ComponentCloudPolicyService(
246 resource_cache
.Pass(),
248 content::BrowserThread::GetMessageLoopProxyForThread(
249 content::BrowserThread::FILE),
250 content::BrowserThread::GetMessageLoopProxyForThread(
251 content::BrowserThread::IO
)));
254 DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
255 chromeos::SessionManagerClient
* session_manager_client
,
256 chromeos::DeviceSettingsService
* device_settings_service
,
257 chromeos::CrosSettings
* cros_settings
,
258 AffiliatedInvalidationServiceProvider
* invalidation_service_provider
,
259 scoped_refptr
<base::SequencedTaskRunner
> store_background_task_runner
,
260 scoped_refptr
<base::SequencedTaskRunner
> extension_cache_task_runner
,
261 scoped_refptr
<base::SequencedTaskRunner
>
262 external_data_service_backend_task_runner
,
263 scoped_refptr
<base::SequencedTaskRunner
> io_task_runner
,
264 scoped_refptr
<net::URLRequestContextGetter
> request_context
)
265 : session_manager_client_(session_manager_client
),
266 device_settings_service_(device_settings_service
),
267 cros_settings_(cros_settings
),
268 invalidation_service_provider_(invalidation_service_provider
),
269 device_management_service_(nullptr),
270 waiting_for_cros_settings_(false),
271 orphan_extension_cache_deletion_state_(NOT_STARTED
),
272 store_background_task_runner_(store_background_task_runner
),
273 extension_cache_task_runner_(extension_cache_task_runner
),
274 request_context_(request_context
),
275 local_accounts_subscription_(cros_settings_
->AddSettingsObserver(
276 chromeos::kAccountsPrefDeviceLocalAccounts
,
277 base::Bind(&DeviceLocalAccountPolicyService::
278 UpdateAccountListIfNonePending
,
279 base::Unretained(this)))),
280 weak_factory_(this) {
281 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_COMPONENT_POLICY
,
282 &component_policy_cache_root_
));
283 external_data_service_
.reset(new DeviceLocalAccountExternalDataService(
285 external_data_service_backend_task_runner
,
290 DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() {
291 DCHECK(!request_context_
.get());
292 DCHECK(policy_brokers_
.empty());
295 void DeviceLocalAccountPolicyService::Shutdown() {
296 device_management_service_
= nullptr;
297 request_context_
= nullptr;
298 DeleteBrokers(&policy_brokers_
);
301 void DeviceLocalAccountPolicyService::Connect(
302 DeviceManagementService
* device_management_service
) {
303 DCHECK(!device_management_service_
);
304 device_management_service_
= device_management_service
;
306 // Connect the brokers.
307 for (PolicyBrokerMap::iterator
it(policy_brokers_
.begin());
308 it
!= policy_brokers_
.end(); ++it
) {
309 it
->second
->ConnectIfPossible(device_settings_service_
,
310 device_management_service_
,
315 DeviceLocalAccountPolicyBroker
*
316 DeviceLocalAccountPolicyService::GetBrokerForUser(
317 const std::string
& user_id
) {
318 PolicyBrokerMap::iterator entry
= policy_brokers_
.find(user_id
);
319 if (entry
== policy_brokers_
.end())
322 return entry
->second
;
325 bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser(
326 const std::string
& user_id
) {
327 DeviceLocalAccountPolicyBroker
* broker
= GetBrokerForUser(user_id
);
328 return broker
&& broker
->core()->store()->is_managed();
331 void DeviceLocalAccountPolicyService::AddObserver(Observer
* observer
) {
332 observers_
.AddObserver(observer
);
335 void DeviceLocalAccountPolicyService::RemoveObserver(Observer
* observer
) {
336 observers_
.RemoveObserver(observer
);
339 bool DeviceLocalAccountPolicyService::IsExtensionCacheDirectoryBusy(
340 const std::string
& account_id
) {
341 return busy_extension_cache_directories_
.find(account_id
) !=
342 busy_extension_cache_directories_
.end();
345 void DeviceLocalAccountPolicyService::StartExtensionCachesIfPossible() {
346 for (PolicyBrokerMap::iterator it
= policy_brokers_
.begin();
347 it
!= policy_brokers_
.end(); ++it
) {
348 if (!it
->second
->extension_loader()->IsCacheRunning() &&
349 !IsExtensionCacheDirectoryBusy(it
->second
->account_id())) {
350 it
->second
->extension_loader()->StartCache(extension_cache_task_runner_
);
355 bool DeviceLocalAccountPolicyService::StartExtensionCacheForAccountIfPresent(
356 const std::string
& account_id
) {
357 for (PolicyBrokerMap::iterator it
= policy_brokers_
.begin();
358 it
!= policy_brokers_
.end(); ++it
) {
359 if (it
->second
->account_id() == account_id
) {
360 DCHECK(!it
->second
->extension_loader()->IsCacheRunning());
361 it
->second
->extension_loader()->StartCache(extension_cache_task_runner_
);
368 void DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted() {
369 DCHECK_EQ(IN_PROGRESS
, orphan_extension_cache_deletion_state_
);
371 orphan_extension_cache_deletion_state_
= DONE
;
372 StartExtensionCachesIfPossible();
375 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown(
376 const std::string
& account_id
) {
377 DCHECK_NE(NOT_STARTED
, orphan_extension_cache_deletion_state_
);
378 DCHECK(IsExtensionCacheDirectoryBusy(account_id
));
380 // The account with |account_id| was deleted and the broker for it has shut
383 if (StartExtensionCacheForAccountIfPresent(account_id
)) {
384 // If another account with the same ID was created in the meantime, its
385 // extension cache is started, reusing the cache directory. The directory no
386 // longer needs to be marked as busy in this case.
387 busy_extension_cache_directories_
.erase(account_id
);
391 // If no account with |account_id| exists anymore, the cache directory should
392 // be removed. The directory must stay marked as busy while the removal is in
394 extension_cache_task_runner_
->PostTaskAndReply(
396 base::Bind(&DeleteObsoleteExtensionCache
, account_id
),
397 base::Bind(&DeviceLocalAccountPolicyService::
398 OnObsoleteExtensionCacheDeleted
,
399 weak_factory_
.GetWeakPtr(),
403 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted(
404 const std::string
& account_id
) {
405 DCHECK_EQ(DONE
, orphan_extension_cache_deletion_state_
);
406 DCHECK(IsExtensionCacheDirectoryBusy(account_id
));
408 // The cache directory for |account_id| has been deleted. The directory no
409 // longer needs to be marked as busy.
410 busy_extension_cache_directories_
.erase(account_id
);
412 // If another account with the same ID was created in the meantime, start its
413 // extension cache, creating a new cache directory.
414 StartExtensionCacheForAccountIfPresent(account_id
);
417 void DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending() {
418 // Avoid unnecessary calls to UpdateAccountList(): If an earlier call is still
419 // pending (because the |cros_settings_| are not trusted yet), the updated
420 // account list will be processed by that call when it eventually runs.
421 if (!waiting_for_cros_settings_
)
425 void DeviceLocalAccountPolicyService::UpdateAccountList() {
426 chromeos::CrosSettingsProvider::TrustedStatus status
=
427 cros_settings_
->PrepareTrustedValues(
428 base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList
,
429 weak_factory_
.GetWeakPtr()));
431 case chromeos::CrosSettingsProvider::TRUSTED
:
432 waiting_for_cros_settings_
= false;
434 case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED
:
435 waiting_for_cros_settings_
= true;
437 case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED
:
438 waiting_for_cros_settings_
= false;
442 // Update |policy_brokers_|, keeping existing entries.
443 PolicyBrokerMap old_policy_brokers
;
444 policy_brokers_
.swap(old_policy_brokers
);
445 std::set
<std::string
> subdirectories_to_keep
;
446 const std::vector
<DeviceLocalAccount
> device_local_accounts
=
447 GetDeviceLocalAccounts(cros_settings_
);
448 for (std::vector
<DeviceLocalAccount
>::const_iterator it
=
449 device_local_accounts
.begin();
450 it
!= device_local_accounts
.end(); ++it
) {
451 PolicyBrokerMap::iterator broker_it
= old_policy_brokers
.find(it
->user_id
);
453 scoped_ptr
<DeviceLocalAccountPolicyBroker
> broker
;
454 bool broker_initialized
= false;
455 if (broker_it
!= old_policy_brokers
.end()) {
456 // Reuse the existing broker if present.
457 broker
.reset(broker_it
->second
);
458 old_policy_brokers
.erase(broker_it
);
459 broker_initialized
= true;
461 scoped_ptr
<DeviceLocalAccountPolicyStore
> store(
462 new DeviceLocalAccountPolicyStore(it
->account_id
,
463 session_manager_client_
,
464 device_settings_service_
,
465 store_background_task_runner_
));
466 scoped_refptr
<DeviceLocalAccountExternalDataManager
>
467 external_data_manager
=
468 external_data_service_
->GetExternalDataManager(it
->account_id
,
470 broker
.reset(new DeviceLocalAccountPolicyBroker(
472 component_policy_cache_root_
.Append(
473 GetCacheSubdirectoryForAccountID(it
->account_id
)),
475 external_data_manager
,
476 base::Bind(&DeviceLocalAccountPolicyService::NotifyPolicyUpdated
,
477 base::Unretained(this),
479 base::ThreadTaskRunnerHandle::Get(),
480 invalidation_service_provider_
));
483 // Fire up the cloud connection for fetching policy for the account from
484 // the cloud if this is an enterprise-managed device.
485 broker
->ConnectIfPossible(device_settings_service_
,
486 device_management_service_
,
489 policy_brokers_
[it
->user_id
] = broker
.release();
490 if (!broker_initialized
) {
491 // The broker must be initialized after it has been added to
492 // |policy_brokers_|.
493 policy_brokers_
[it
->user_id
]->Initialize();
496 subdirectories_to_keep
.insert(
497 GetCacheSubdirectoryForAccountID(it
->account_id
));
500 if (orphan_extension_cache_deletion_state_
== NOT_STARTED
) {
501 DCHECK(old_policy_brokers
.empty());
502 DCHECK(busy_extension_cache_directories_
.empty());
504 // If this method is running for the first time, no extension caches have
505 // been started yet. Take this opportunity to do a clean-up by removing
506 // orphaned cache directories not found in |subdirectories_to_keep| from the
508 orphan_extension_cache_deletion_state_
= IN_PROGRESS
;
510 base::FilePath cache_root_dir
;
511 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS
,
513 extension_cache_task_runner_
->PostTaskAndReply(
516 &DeleteOrphanedCaches
, cache_root_dir
, subdirectories_to_keep
),
518 &DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted
,
519 weak_factory_
.GetWeakPtr()));
521 // Start the extension caches for all brokers. These belong to accounts in
522 // |account_ids| and are not affected by the clean-up.
523 StartExtensionCachesIfPossible();
525 // If this method has run before, obsolete brokers may exist. Shut down
526 // their extension caches and delete the brokers.
527 DeleteBrokers(&old_policy_brokers
);
529 if (orphan_extension_cache_deletion_state_
== DONE
) {
530 // If the initial clean-up of orphaned cache directories has been
531 // complete, start any extension caches that are not running yet but can
532 // be started now because their cache directories are not busy.
533 StartExtensionCachesIfPossible();
537 // Purge the component policy caches of any accounts that have been removed.
538 // Do this only after any obsolete brokers have been destroyed.
539 // TODO(joaodasilva): for now this must be posted to the FILE thread,
540 // to avoid racing with the ComponentCloudPolicyStore. Use a task runner
541 // once that class supports another background thread too.
542 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE
,
543 base::Bind(&DeleteOrphanedCaches
,
544 component_policy_cache_root_
,
545 subdirectories_to_keep
));
547 FOR_EACH_OBSERVER(Observer
, observers_
, OnDeviceLocalAccountsChanged());
550 void DeviceLocalAccountPolicyService::DeleteBrokers(PolicyBrokerMap
* map
) {
551 for (PolicyBrokerMap::iterator it
= map
->begin(); it
!= map
->end(); ++it
) {
552 scoped_refptr
<chromeos::DeviceLocalAccountExternalPolicyLoader
>
553 extension_loader
= it
->second
->extension_loader();
554 if (extension_loader
->IsCacheRunning()) {
555 DCHECK(!IsExtensionCacheDirectoryBusy(it
->second
->account_id()));
556 busy_extension_cache_directories_
.insert(it
->second
->account_id());
557 extension_loader
->StopCache(base::Bind(
558 &DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown
,
559 weak_factory_
.GetWeakPtr(),
560 it
->second
->account_id()));
568 DeviceLocalAccountPolicyBroker
*
569 DeviceLocalAccountPolicyService::GetBrokerForStore(
570 CloudPolicyStore
* store
) {
571 for (PolicyBrokerMap::iterator
it(policy_brokers_
.begin());
572 it
!= policy_brokers_
.end(); ++it
) {
573 if (it
->second
->core()->store() == store
)
579 void DeviceLocalAccountPolicyService::NotifyPolicyUpdated(
580 const std::string
& user_id
) {
581 FOR_EACH_OBSERVER(Observer
, observers_
, OnPolicyUpdated(user_id
));
584 } // namespace policy