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