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