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.
4
5 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
6
7 #include <vector>
8
9 #include "base/bind.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"
37 #include "url/gurl.h"
38
39 namespace em = enterprise_management;
40
41 namespace policy {
42
43 namespace {
44
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).
CreateClient(chromeos::DeviceSettingsService * device_settings_service,DeviceManagementService * device_management_service,scoped_refptr<net::URLRequestContextGetter> system_request_context)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();
53 if (!policy_data ||
54 !policy_data->has_request_token() ||
55 !policy_data->has_device_id() ||
56 !device_management_service) {
57 return scoped_ptr<CloudPolicyClient>();
58 }
59
60 scoped_refptr<net::URLRequestContextGetter> request_context =
61 new SystemPolicyRequestContext(
62 system_request_context,
63 content::GetUserAgent(GURL(
64 device_management_service->GetServerUrl())));
65
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());
72 return client.Pass();
73 }
74
75 // Get the subdirectory of the cache directory in which force-installed
76 // extensions are cached for |account_id|.
GetCacheSubdirectoryForAccountID(const std::string & account_id)77 std::string GetCacheSubdirectoryForAccountID(const std::string& account_id) {
78 return base::HexEncode(account_id.c_str(), account_id.size());
79 }
80
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.
DeleteOrphanedExtensionCaches(const std::set<std::string> & subdirectories_to_keep)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,
88 &cache_root_dir));
89 base::FileEnumerator enumerator(cache_root_dir,
90 false,
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);
98 }
99 }
100 }
101
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.
DeleteObsoleteExtensionCache(const std::string & account_id_to_delete)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,
108 &cache_root_dir));
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);
113 }
114
115 } // namespace
116
DeviceLocalAccountPolicyBroker(const DeviceLocalAccount & account,scoped_ptr<DeviceLocalAccountPolicyStore> store,scoped_refptr<DeviceLocalAccountExternalDataManager> external_data_manager,const scoped_refptr<base::SequencedTaskRunner> & task_runner)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()),
128 store_.get(),
129 task_runner) {
130 base::FilePath cache_root_dir;
131 CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
132 &cache_root_dir));
133 extension_loader_ = new chromeos::DeviceLocalAccountExternalPolicyLoader(
134 store_.get(),
135 cache_root_dir.Append(
136 GetCacheSubdirectoryForAccountID(account.account_id)));
137 }
138
~DeviceLocalAccountPolicyBroker()139 DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {
140 external_data_manager_->SetPolicyStore(NULL);
141 external_data_manager_->Disconnect();
142 }
143
Initialize()144 void DeviceLocalAccountPolicyBroker::Initialize() {
145 store_->Load();
146 }
147
ConnectIfPossible(chromeos::DeviceSettingsService * device_settings_service,DeviceManagementService * device_management_service,scoped_refptr<net::URLRequestContextGetter> request_context)148 void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
149 chromeos::DeviceSettingsService* device_settings_service,
150 DeviceManagementService* device_management_service,
151 scoped_refptr<net::URLRequestContextGetter> request_context) {
152 if (core_.client())
153 return;
154
155 scoped_ptr<CloudPolicyClient> client(CreateClient(device_settings_service,
156 device_management_service,
157 request_context));
158 if (!client)
159 return;
160
161 core_.Connect(client.Pass());
162 external_data_manager_->Connect(request_context);
163 core_.StartRefreshScheduler();
164 UpdateRefreshDelay();
165 }
166
UpdateRefreshDelay()167 void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() {
168 if (core_.refresh_scheduler()) {
169 const Value* policy_value =
170 store_->policy_map().GetValue(key::kPolicyRefreshRate);
171 int delay = 0;
172 if (policy_value && policy_value->GetAsInteger(&delay))
173 core_.refresh_scheduler()->SetRefreshDelay(delay);
174 }
175 }
176
GetDisplayName() const177 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);
183 return display_name;
184 }
185
DeviceLocalAccountPolicyService(chromeos::SessionManagerClient * session_manager_client,chromeos::DeviceSettingsService * device_settings_service,chromeos::CrosSettings * cros_settings,scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner,scoped_refptr<base::SequencedTaskRunner> external_data_service_backend_task_runner,scoped_refptr<base::SequencedTaskRunner> io_task_runner,scoped_refptr<net::URLRequestContextGetter> request_context)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(
212 this,
213 external_data_service_backend_task_runner,
214 io_task_runner));
215 UpdateAccountList();
216 }
217
~DeviceLocalAccountPolicyService()218 DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() {
219 DCHECK(!request_context_);
220 DCHECK(policy_brokers_.empty());
221 }
222
Shutdown()223 void DeviceLocalAccountPolicyService::Shutdown() {
224 device_management_service_ = NULL;
225 request_context_ = NULL;
226 DeleteBrokers(&policy_brokers_);
227 }
228
Connect(DeviceManagementService * device_management_service)229 void DeviceLocalAccountPolicyService::Connect(
230 DeviceManagementService* device_management_service) {
231 DCHECK(!device_management_service_);
232 device_management_service_ = device_management_service;
233
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_,
239 request_context_);
240 }
241 }
242
243 DeviceLocalAccountPolicyBroker*
GetBrokerForUser(const std::string & user_id)244 DeviceLocalAccountPolicyService::GetBrokerForUser(
245 const std::string& user_id) {
246 PolicyBrokerMap::iterator entry = policy_brokers_.find(user_id);
247 if (entry == policy_brokers_.end())
248 return NULL;
249
250 return entry->second;
251 }
252
IsPolicyAvailableForUser(const std::string & user_id)253 bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser(
254 const std::string& user_id) {
255 DeviceLocalAccountPolicyBroker* broker = GetBrokerForUser(user_id);
256 return broker && broker->core()->store()->is_managed();
257 }
258
AddObserver(Observer * observer)259 void DeviceLocalAccountPolicyService::AddObserver(Observer* observer) {
260 observers_.AddObserver(observer);
261 }
262
RemoveObserver(Observer * observer)263 void DeviceLocalAccountPolicyService::RemoveObserver(Observer* observer) {
264 observers_.RemoveObserver(observer);
265 }
266
OnStoreLoaded(CloudPolicyStore * store)267 void DeviceLocalAccountPolicyService::OnStoreLoaded(CloudPolicyStore* store) {
268 DeviceLocalAccountPolicyBroker* broker = GetBrokerForStore(store);
269 DCHECK(broker);
270 if (!broker)
271 return;
272 broker->UpdateRefreshDelay();
273 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(broker->user_id()));
274 }
275
OnStoreError(CloudPolicyStore * store)276 void DeviceLocalAccountPolicyService::OnStoreError(CloudPolicyStore* store) {
277 DeviceLocalAccountPolicyBroker* broker = GetBrokerForStore(store);
278 DCHECK(broker);
279 if (!broker)
280 return;
281 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(broker->user_id()));
282 }
283
IsExtensionCacheDirectoryBusy(const std::string & account_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();
288 }
289
StartExtensionCachesIfPossible()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_);
296 }
297 }
298 }
299
StartExtensionCacheForAccountIfPresent(const std::string & account_id)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_);
307 return true;
308 }
309 }
310 return false;
311 }
312
OnOrphanedExtensionCachesDeleted()313 void DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted() {
314 DCHECK_EQ(IN_PROGRESS, orphan_cache_deletion_state_);
315
316 orphan_cache_deletion_state_ = DONE;
317 StartExtensionCachesIfPossible();
318 }
319
OnObsoleteExtensionCacheShutdown(const std::string & account_id)320 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown(
321 const std::string& account_id) {
322 DCHECK_NE(NOT_STARTED, orphan_cache_deletion_state_);
323 DCHECK(IsExtensionCacheDirectoryBusy(account_id));
324
325 // The account with |account_id| was deleted and the broker for it has shut
326 // down completely.
327
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);
333 return;
334 }
335
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
338 // progress.
339 extension_cache_task_runner_->PostTaskAndReply(
340 FROM_HERE,
341 base::Bind(&DeleteObsoleteExtensionCache, account_id),
342 base::Bind(&DeviceLocalAccountPolicyService::
343 OnObsoleteExtensionCacheDeleted,
344 weak_factory_.GetWeakPtr(),
345 account_id));
346 }
347
OnObsoleteExtensionCacheDeleted(const std::string & account_id)348 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted(
349 const std::string& account_id) {
350 DCHECK_EQ(DONE, orphan_cache_deletion_state_);
351 DCHECK(IsExtensionCacheDirectoryBusy(account_id));
352
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);
356
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);
360 }
361
UpdateAccountListIfNonePending()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_)
367 UpdateAccountList();
368 }
369
UpdateAccountList()370 void DeviceLocalAccountPolicyService::UpdateAccountList() {
371 chromeos::CrosSettingsProvider::TrustedStatus status =
372 cros_settings_->PrepareTrustedValues(
373 base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList,
374 weak_factory_.GetWeakPtr()));
375 switch (status) {
376 case chromeos::CrosSettingsProvider::TRUSTED:
377 waiting_for_cros_settings_ = false;
378 break;
379 case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
380 waiting_for_cros_settings_ = true;
381 return;
382 case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
383 waiting_for_cros_settings_ = false;
384 return;
385 }
386
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);
397
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;
405 } else {
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,
415 store.get());
416 broker.reset(new DeviceLocalAccountPolicyBroker(
417 *it,
418 store.Pass(),
419 external_data_manager,
420 base::MessageLoopProxy::current()));
421 }
422
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_,
427 request_context_);
428
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();
434 }
435
436 if (orphan_cache_deletion_state_ == NOT_STARTED) {
437 subdirectories_to_keep.insert(
438 GetCacheSubdirectoryForAccountID(it->account_id));
439 }
440 }
441
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());
446 }
447
448 if (orphan_cache_deletion_state_ == NOT_STARTED) {
449 DCHECK(old_policy_brokers.empty());
450 DCHECK(busy_extension_cache_directories_.empty());
451
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
455 // cache directory.
456 orphan_cache_deletion_state_ = IN_PROGRESS;
457 extension_cache_task_runner_->PostTaskAndReply(
458 FROM_HERE,
459 base::Bind(&DeleteOrphanedExtensionCaches, subdirectories_to_keep),
460 base::Bind(&DeviceLocalAccountPolicyService::
461 OnOrphanedExtensionCachesDeleted,
462 weak_factory_.GetWeakPtr()));
463
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();
467 } else {
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);
471
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();
477 }
478 }
479
480 FOR_EACH_OBSERVER(Observer, observers_, OnDeviceLocalAccountsChanged());
481 }
482
DeleteBrokers(PolicyBrokerMap * map)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()));
495 }
496 delete it->second;
497 }
498 map->clear();
499 }
500
501 DeviceLocalAccountPolicyBroker*
GetBrokerForStore(CloudPolicyStore * store)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)
507 return it->second;
508 }
509 return NULL;
510 }
511
512 } // namespace policy
513