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