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