• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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