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 USER_AFFILIATION_MANAGED
,
69 NULL
, device_management_service
, request_context
));
70 client
->SetupRegistration(policy_data
->request_token(),
71 policy_data
->device_id());
75 // Get the subdirectory of the cache directory in which force-installed
76 // extensions are cached for |account_id|.
77 std::string
GetCacheSubdirectoryForAccountID(const std::string
& account_id
) {
78 return base::HexEncode(account_id
.c_str(), account_id
.size());
81 // Cleans up the cache directory by removing subdirectories that are not found
82 // in |subdirectories_to_keep|. Only caches whose cache directory is found in
83 // |subdirectories_to_keep| may be running while the clean-up is in progress.
84 void DeleteOrphanedExtensionCaches(
85 const std::set
<std::string
>& subdirectories_to_keep
) {
86 base::FilePath cache_root_dir
;
87 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS
,
89 base::FileEnumerator
enumerator(cache_root_dir
,
91 base::FileEnumerator::DIRECTORIES
);
92 for (base::FilePath path
= enumerator
.Next(); !path
.empty();
93 path
= enumerator
.Next()) {
94 const std::string
subdirectory(path
.BaseName().MaybeAsASCII());
95 if (subdirectories_to_keep
.find(subdirectory
) ==
96 subdirectories_to_keep
.end()) {
97 base::DeleteFile(path
, true);
102 // Removes the subdirectory belonging to |account_id_to_delete| from the cache
103 // directory. No cache belonging to |account_id_to_delete| may be running while
104 // the removal is in progress.
105 void DeleteObsoleteExtensionCache(const std::string
& account_id_to_delete
) {
106 base::FilePath cache_root_dir
;
107 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS
,
109 const base::FilePath path
= cache_root_dir
110 .Append(GetCacheSubdirectoryForAccountID(account_id_to_delete
));
111 if (base::DirectoryExists(path
))
112 base::DeleteFile(path
, true);
117 DeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker(
118 const DeviceLocalAccount
& account
,
119 scoped_ptr
<DeviceLocalAccountPolicyStore
> store
,
120 scoped_refptr
<DeviceLocalAccountExternalDataManager
> external_data_manager
,
121 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
)
122 : account_id_(account
.account_id
),
123 user_id_(account
.user_id
),
124 store_(store
.Pass()),
125 external_data_manager_(external_data_manager
),
126 core_(PolicyNamespaceKey(dm_protocol::kChromePublicAccountPolicyType
,
127 store_
->account_id()),
130 base::FilePath cache_root_dir
;
131 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS
,
133 extension_loader_
= new chromeos::DeviceLocalAccountExternalPolicyLoader(
135 cache_root_dir
.Append(
136 GetCacheSubdirectoryForAccountID(account
.account_id
)));
139 DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {
140 external_data_manager_
->SetPolicyStore(NULL
);
141 external_data_manager_
->Disconnect();
144 void DeviceLocalAccountPolicyBroker::Initialize() {
148 void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
149 chromeos::DeviceSettingsService
* device_settings_service
,
150 DeviceManagementService
* device_management_service
,
151 scoped_refptr
<net::URLRequestContextGetter
> request_context
) {
155 scoped_ptr
<CloudPolicyClient
> client(CreateClient(device_settings_service
,
156 device_management_service
,
161 core_
.Connect(client
.Pass());
162 external_data_manager_
->Connect(request_context
);
163 core_
.StartRefreshScheduler();
164 UpdateRefreshDelay();
167 void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() {
168 if (core_
.refresh_scheduler()) {
169 const base::Value
* policy_value
=
170 store_
->policy_map().GetValue(key::kPolicyRefreshRate
);
172 if (policy_value
&& policy_value
->GetAsInteger(&delay
))
173 core_
.refresh_scheduler()->SetRefreshDelay(delay
);
177 std::string
DeviceLocalAccountPolicyBroker::GetDisplayName() const {
178 std::string display_name
;
179 const base::Value
* display_name_value
=
180 store_
->policy_map().GetValue(policy::key::kUserDisplayName
);
181 if (display_name_value
)
182 display_name_value
->GetAsString(&display_name
);
186 DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
187 chromeos::SessionManagerClient
* session_manager_client
,
188 chromeos::DeviceSettingsService
* device_settings_service
,
189 chromeos::CrosSettings
* cros_settings
,
190 scoped_refptr
<base::SequencedTaskRunner
> store_background_task_runner
,
191 scoped_refptr
<base::SequencedTaskRunner
> extension_cache_task_runner
,
192 scoped_refptr
<base::SequencedTaskRunner
>
193 external_data_service_backend_task_runner
,
194 scoped_refptr
<base::SequencedTaskRunner
> io_task_runner
,
195 scoped_refptr
<net::URLRequestContextGetter
> request_context
)
196 : session_manager_client_(session_manager_client
),
197 device_settings_service_(device_settings_service
),
198 cros_settings_(cros_settings
),
199 device_management_service_(NULL
),
200 waiting_for_cros_settings_(false),
201 orphan_cache_deletion_state_(NOT_STARTED
),
202 store_background_task_runner_(store_background_task_runner
),
203 extension_cache_task_runner_(extension_cache_task_runner
),
204 request_context_(request_context
),
205 local_accounts_subscription_(cros_settings_
->AddSettingsObserver(
206 chromeos::kAccountsPrefDeviceLocalAccounts
,
207 base::Bind(&DeviceLocalAccountPolicyService::
208 UpdateAccountListIfNonePending
,
209 base::Unretained(this)))),
210 weak_factory_(this) {
211 external_data_service_
.reset(new DeviceLocalAccountExternalDataService(
213 external_data_service_backend_task_runner
,
218 DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() {
219 DCHECK(!request_context_
);
220 DCHECK(policy_brokers_
.empty());
223 void DeviceLocalAccountPolicyService::Shutdown() {
224 device_management_service_
= NULL
;
225 request_context_
= NULL
;
226 DeleteBrokers(&policy_brokers_
);
229 void DeviceLocalAccountPolicyService::Connect(
230 DeviceManagementService
* device_management_service
) {
231 DCHECK(!device_management_service_
);
232 device_management_service_
= device_management_service
;
234 // Connect the brokers.
235 for (PolicyBrokerMap::iterator
it(policy_brokers_
.begin());
236 it
!= policy_brokers_
.end(); ++it
) {
237 it
->second
->ConnectIfPossible(device_settings_service_
,
238 device_management_service_
,
243 DeviceLocalAccountPolicyBroker
*
244 DeviceLocalAccountPolicyService::GetBrokerForUser(
245 const std::string
& user_id
) {
246 PolicyBrokerMap::iterator entry
= policy_brokers_
.find(user_id
);
247 if (entry
== policy_brokers_
.end())
250 return entry
->second
;
253 bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser(
254 const std::string
& user_id
) {
255 DeviceLocalAccountPolicyBroker
* broker
= GetBrokerForUser(user_id
);
256 return broker
&& broker
->core()->store()->is_managed();
259 void DeviceLocalAccountPolicyService::AddObserver(Observer
* observer
) {
260 observers_
.AddObserver(observer
);
263 void DeviceLocalAccountPolicyService::RemoveObserver(Observer
* observer
) {
264 observers_
.RemoveObserver(observer
);
267 void DeviceLocalAccountPolicyService::OnStoreLoaded(CloudPolicyStore
* store
) {
268 DeviceLocalAccountPolicyBroker
* broker
= GetBrokerForStore(store
);
272 broker
->UpdateRefreshDelay();
273 FOR_EACH_OBSERVER(Observer
, observers_
, OnPolicyUpdated(broker
->user_id()));
276 void DeviceLocalAccountPolicyService::OnStoreError(CloudPolicyStore
* store
) {
277 DeviceLocalAccountPolicyBroker
* broker
= GetBrokerForStore(store
);
281 FOR_EACH_OBSERVER(Observer
, observers_
, OnPolicyUpdated(broker
->user_id()));
284 bool DeviceLocalAccountPolicyService::IsExtensionCacheDirectoryBusy(
285 const std::string
& account_id
) {
286 return busy_extension_cache_directories_
.find(account_id
) !=
287 busy_extension_cache_directories_
.end();
290 void DeviceLocalAccountPolicyService::StartExtensionCachesIfPossible() {
291 for (PolicyBrokerMap::iterator it
= policy_brokers_
.begin();
292 it
!= policy_brokers_
.end(); ++it
) {
293 if (!it
->second
->extension_loader()->IsCacheRunning() &&
294 !IsExtensionCacheDirectoryBusy(it
->second
->account_id())) {
295 it
->second
->extension_loader()->StartCache(extension_cache_task_runner_
);
300 bool DeviceLocalAccountPolicyService::StartExtensionCacheForAccountIfPresent(
301 const std::string
& account_id
) {
302 for (PolicyBrokerMap::iterator it
= policy_brokers_
.begin();
303 it
!= policy_brokers_
.end(); ++it
) {
304 if (it
->second
->account_id() == account_id
) {
305 DCHECK(!it
->second
->extension_loader()->IsCacheRunning());
306 it
->second
->extension_loader()->StartCache(extension_cache_task_runner_
);
313 void DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted() {
314 DCHECK_EQ(IN_PROGRESS
, orphan_cache_deletion_state_
);
316 orphan_cache_deletion_state_
= DONE
;
317 StartExtensionCachesIfPossible();
320 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown(
321 const std::string
& account_id
) {
322 DCHECK_NE(NOT_STARTED
, orphan_cache_deletion_state_
);
323 DCHECK(IsExtensionCacheDirectoryBusy(account_id
));
325 // The account with |account_id| was deleted and the broker for it has shut
328 if (StartExtensionCacheForAccountIfPresent(account_id
)) {
329 // If another account with the same ID was created in the meantime, its
330 // extension cache is started, reusing the cache directory. The directory no
331 // longer needs to be marked as busy in this case.
332 busy_extension_cache_directories_
.erase(account_id
);
336 // If no account with |account_id| exists anymore, the cache directory should
337 // be removed. The directory must stay marked as busy while the removal is in
339 extension_cache_task_runner_
->PostTaskAndReply(
341 base::Bind(&DeleteObsoleteExtensionCache
, account_id
),
342 base::Bind(&DeviceLocalAccountPolicyService::
343 OnObsoleteExtensionCacheDeleted
,
344 weak_factory_
.GetWeakPtr(),
348 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted(
349 const std::string
& account_id
) {
350 DCHECK_EQ(DONE
, orphan_cache_deletion_state_
);
351 DCHECK(IsExtensionCacheDirectoryBusy(account_id
));
353 // The cache directory for |account_id| has been deleted. The directory no
354 // longer needs to be marked as busy.
355 busy_extension_cache_directories_
.erase(account_id
);
357 // If another account with the same ID was created in the meantime, start its
358 // extension cache, creating a new cache directory.
359 StartExtensionCacheForAccountIfPresent(account_id
);
362 void DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending() {
363 // Avoid unnecessary calls to UpdateAccountList(): If an earlier call is still
364 // pending (because the |cros_settings_| are not trusted yet), the updated
365 // account list will be processed by that call when it eventually runs.
366 if (!waiting_for_cros_settings_
)
370 void DeviceLocalAccountPolicyService::UpdateAccountList() {
371 chromeos::CrosSettingsProvider::TrustedStatus status
=
372 cros_settings_
->PrepareTrustedValues(
373 base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList
,
374 weak_factory_
.GetWeakPtr()));
376 case chromeos::CrosSettingsProvider::TRUSTED
:
377 waiting_for_cros_settings_
= false;
379 case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED
:
380 waiting_for_cros_settings_
= true;
382 case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED
:
383 waiting_for_cros_settings_
= false;
387 // Update |policy_brokers_|, keeping existing entries.
388 PolicyBrokerMap old_policy_brokers
;
389 policy_brokers_
.swap(old_policy_brokers
);
390 std::set
<std::string
> subdirectories_to_keep
;
391 const std::vector
<DeviceLocalAccount
> device_local_accounts
=
392 GetDeviceLocalAccounts(cros_settings_
);
393 for (std::vector
<DeviceLocalAccount
>::const_iterator it
=
394 device_local_accounts
.begin();
395 it
!= device_local_accounts
.end(); ++it
) {
396 PolicyBrokerMap::iterator broker_it
= old_policy_brokers
.find(it
->user_id
);
398 scoped_ptr
<DeviceLocalAccountPolicyBroker
> broker
;
399 bool broker_initialized
= false;
400 if (broker_it
!= old_policy_brokers
.end()) {
401 // Reuse the existing broker if present.
402 broker
.reset(broker_it
->second
);
403 old_policy_brokers
.erase(broker_it
);
404 broker_initialized
= true;
406 scoped_ptr
<DeviceLocalAccountPolicyStore
> store(
407 new DeviceLocalAccountPolicyStore(it
->account_id
,
408 session_manager_client_
,
409 device_settings_service_
,
410 store_background_task_runner_
));
411 store
->AddObserver(this);
412 scoped_refptr
<DeviceLocalAccountExternalDataManager
>
413 external_data_manager
=
414 external_data_service_
->GetExternalDataManager(it
->account_id
,
416 broker
.reset(new DeviceLocalAccountPolicyBroker(
419 external_data_manager
,
420 base::MessageLoopProxy::current()));
423 // Fire up the cloud connection for fetching policy for the account from
424 // the cloud if this is an enterprise-managed device.
425 broker
->ConnectIfPossible(device_settings_service_
,
426 device_management_service_
,
429 policy_brokers_
[it
->user_id
] = broker
.release();
430 if (!broker_initialized
) {
431 // The broker must be initialized after it has been added to
432 // |policy_brokers_|.
433 policy_brokers_
[it
->user_id
]->Initialize();
436 if (orphan_cache_deletion_state_
== NOT_STARTED
) {
437 subdirectories_to_keep
.insert(
438 GetCacheSubdirectoryForAccountID(it
->account_id
));
442 std::set
<std::string
> obsolete_account_ids
;
443 for (PolicyBrokerMap::const_iterator it
= old_policy_brokers
.begin();
444 it
!= old_policy_brokers
.end(); ++it
) {
445 obsolete_account_ids
.insert(it
->second
->account_id());
448 if (orphan_cache_deletion_state_
== NOT_STARTED
) {
449 DCHECK(old_policy_brokers
.empty());
450 DCHECK(busy_extension_cache_directories_
.empty());
452 // If this method is running for the first time, no extension caches have
453 // been started yet. Take this opportunity to do a clean-up by removing
454 // orphaned cache directories not found in |subdirectories_to_keep| from the
456 orphan_cache_deletion_state_
= IN_PROGRESS
;
457 extension_cache_task_runner_
->PostTaskAndReply(
459 base::Bind(&DeleteOrphanedExtensionCaches
, subdirectories_to_keep
),
460 base::Bind(&DeviceLocalAccountPolicyService::
461 OnOrphanedExtensionCachesDeleted
,
462 weak_factory_
.GetWeakPtr()));
464 // Start the extension caches for all brokers. These belong to accounts in
465 // |account_ids| and are not affected by the clean-up.
466 StartExtensionCachesIfPossible();
468 // If this method has run before, obsolete brokers may exist. Shut down
469 // their extension caches and delete the brokers.
470 DeleteBrokers(&old_policy_brokers
);
472 if (orphan_cache_deletion_state_
== DONE
) {
473 // If the initial clean-up of orphaned cache directories has been
474 // complete, start any extension caches that are not running yet but can
475 // be started now because their cache directories are not busy.
476 StartExtensionCachesIfPossible();
480 FOR_EACH_OBSERVER(Observer
, observers_
, OnDeviceLocalAccountsChanged());
483 void DeviceLocalAccountPolicyService::DeleteBrokers(PolicyBrokerMap
* map
) {
484 for (PolicyBrokerMap::iterator it
= map
->begin(); it
!= map
->end(); ++it
) {
485 it
->second
->core()->store()->RemoveObserver(this);
486 scoped_refptr
<chromeos::DeviceLocalAccountExternalPolicyLoader
>
487 extension_loader
= it
->second
->extension_loader();
488 if (extension_loader
->IsCacheRunning()) {
489 DCHECK(!IsExtensionCacheDirectoryBusy(it
->second
->account_id()));
490 busy_extension_cache_directories_
.insert(it
->second
->account_id());
491 extension_loader
->StopCache(base::Bind(
492 &DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown
,
493 weak_factory_
.GetWeakPtr(),
494 it
->second
->account_id()));
501 DeviceLocalAccountPolicyBroker
*
502 DeviceLocalAccountPolicyService::GetBrokerForStore(
503 CloudPolicyStore
* store
) {
504 for (PolicyBrokerMap::iterator
it(policy_brokers_
.begin());
505 it
!= policy_brokers_
.end(); ++it
) {
506 if (it
->second
->core()->store() == store
)
512 } // namespace policy