Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h" | 5 #include "chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 54 VALIDATION_FAILURE_SIZE); | 54 VALIDATION_FAILURE_SIZE); |
| 55 } | 55 } |
| 56 | 56 |
| 57 // Extracts the domain name from the passed username. | 57 // Extracts the domain name from the passed username. |
| 58 std::string ExtractDomain(const std::string& username) { | 58 std::string ExtractDomain(const std::string& username) { |
| 59 return gaia::ExtractDomainName(gaia::CanonicalizeEmail(username)); | 59 return gaia::ExtractDomainName(gaia::CanonicalizeEmail(username)); |
| 60 } | 60 } |
| 61 | 61 |
| 62 } // namespace | 62 } // namespace |
| 63 | 63 |
| 64 // Helper class for loading legacy policy caches. | |
| 65 class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate, | |
| 66 public UserPolicyDiskCache::Delegate { | |
| 67 public: | |
| 68 typedef base::Callback<void(const std::string&, | |
| 69 const std::string&, | |
| 70 CloudPolicyStore::Status, | |
| 71 std::unique_ptr<em::PolicyFetchResponse>)> | |
| 72 Callback; | |
| 73 | |
| 74 LegacyPolicyCacheLoader( | |
| 75 const base::FilePath& token_cache_file, | |
| 76 const base::FilePath& policy_cache_file, | |
| 77 scoped_refptr<base::SequencedTaskRunner> background_task_runner); | |
| 78 ~LegacyPolicyCacheLoader() override; | |
| 79 | |
| 80 // Starts loading, and reports the result to |callback| when done. | |
| 81 void Load(const Callback& callback); | |
| 82 | |
| 83 // UserPolicyTokenLoader::Delegate: | |
| 84 void OnTokenLoaded(const std::string& token, | |
| 85 const std::string& device_id) override; | |
| 86 | |
| 87 // UserPolicyDiskCache::Delegate: | |
| 88 void OnDiskCacheLoaded(UserPolicyDiskCache::LoadResult result, | |
| 89 const em::CachedCloudPolicyResponse& policy) override; | |
| 90 | |
| 91 private: | |
| 92 // Checks whether the load operations from the legacy caches completed. If so, | |
| 93 // fires the appropriate notification. | |
| 94 void CheckLoadFinished(); | |
| 95 | |
| 96 // Maps a disk cache LoadResult to a CloudPolicyStore::Status. | |
| 97 static CloudPolicyStore::Status TranslateLoadResult( | |
| 98 UserPolicyDiskCache::LoadResult result); | |
| 99 | |
| 100 scoped_refptr<UserPolicyTokenLoader> token_loader_; | |
| 101 scoped_refptr<UserPolicyDiskCache> policy_cache_; | |
| 102 | |
| 103 std::string dm_token_; | |
| 104 std::string device_id_; | |
| 105 std::unique_ptr<em::PolicyFetchResponse> policy_; | |
| 106 CloudPolicyStore::Status status_; | |
| 107 | |
| 108 Callback callback_; | |
| 109 | |
| 110 base::WeakPtrFactory<LegacyPolicyCacheLoader> weak_factory_; | |
| 111 | |
| 112 DISALLOW_COPY_AND_ASSIGN(LegacyPolicyCacheLoader); | |
| 113 }; | |
| 114 | |
| 115 LegacyPolicyCacheLoader::LegacyPolicyCacheLoader( | |
| 116 const base::FilePath& token_cache_file, | |
| 117 const base::FilePath& policy_cache_file, | |
| 118 scoped_refptr<base::SequencedTaskRunner> background_task_runner) | |
| 119 : status_(CloudPolicyStore::STATUS_OK), | |
| 120 weak_factory_(this) { | |
| 121 token_loader_ = new UserPolicyTokenLoader(weak_factory_.GetWeakPtr(), | |
| 122 token_cache_file, | |
| 123 background_task_runner); | |
| 124 policy_cache_ = new UserPolicyDiskCache(weak_factory_.GetWeakPtr(), | |
| 125 policy_cache_file, | |
| 126 background_task_runner); | |
| 127 } | |
| 128 | |
| 129 LegacyPolicyCacheLoader::~LegacyPolicyCacheLoader() {} | |
| 130 | |
| 131 void LegacyPolicyCacheLoader::Load(const Callback& callback) { | |
| 132 callback_ = callback; | |
| 133 token_loader_->Load(); | |
| 134 policy_cache_->Load(); | |
| 135 } | |
| 136 | |
| 137 void LegacyPolicyCacheLoader::OnTokenLoaded(const std::string& token, | |
| 138 const std::string& device_id) { | |
| 139 dm_token_ = token; | |
| 140 device_id_ = device_id; | |
| 141 token_loader_ = NULL; | |
| 142 CheckLoadFinished(); | |
| 143 } | |
| 144 | |
| 145 void LegacyPolicyCacheLoader::OnDiskCacheLoaded( | |
| 146 UserPolicyDiskCache::LoadResult result, | |
| 147 const em::CachedCloudPolicyResponse& policy) { | |
| 148 status_ = TranslateLoadResult(result); | |
| 149 if (result == UserPolicyDiskCache::LOAD_RESULT_SUCCESS) { | |
| 150 if (policy.has_cloud_policy()) | |
| 151 policy_.reset(new em::PolicyFetchResponse(policy.cloud_policy())); | |
| 152 } else { | |
| 153 LOG(WARNING) << "Failed to load legacy policy cache: " << result; | |
| 154 } | |
| 155 policy_cache_ = NULL; | |
| 156 CheckLoadFinished(); | |
| 157 } | |
| 158 | |
| 159 void LegacyPolicyCacheLoader::CheckLoadFinished() { | |
| 160 if (!token_loader_.get() && !policy_cache_.get()) | |
| 161 callback_.Run(dm_token_, device_id_, status_, std::move(policy_)); | |
| 162 } | |
| 163 | |
| 164 // static | |
| 165 CloudPolicyStore::Status LegacyPolicyCacheLoader::TranslateLoadResult( | |
| 166 UserPolicyDiskCache::LoadResult result) { | |
| 167 switch (result) { | |
| 168 case UserPolicyDiskCache::LOAD_RESULT_SUCCESS: | |
| 169 case UserPolicyDiskCache::LOAD_RESULT_NOT_FOUND: | |
| 170 return CloudPolicyStore::STATUS_OK; | |
| 171 case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR: | |
| 172 case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR: | |
| 173 return CloudPolicyStore::STATUS_LOAD_ERROR; | |
| 174 } | |
| 175 NOTREACHED(); | |
| 176 return CloudPolicyStore::STATUS_OK; | |
| 177 } | |
| 178 | |
| 179 UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS( | 64 UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS( |
| 180 chromeos::CryptohomeClient* cryptohome_client, | 65 chromeos::CryptohomeClient* cryptohome_client, |
| 181 chromeos::SessionManagerClient* session_manager_client, | 66 chromeos::SessionManagerClient* session_manager_client, |
| 182 scoped_refptr<base::SequencedTaskRunner> background_task_runner, | 67 scoped_refptr<base::SequencedTaskRunner> background_task_runner, |
| 183 const AccountId& account_id, | 68 const AccountId& account_id, |
| 184 const base::FilePath& user_policy_key_dir, | 69 const base::FilePath& user_policy_key_dir) |
| 185 const base::FilePath& legacy_token_cache_file, | |
| 186 const base::FilePath& legacy_policy_cache_file) | |
| 187 : UserCloudPolicyStoreBase(background_task_runner), | 70 : UserCloudPolicyStoreBase(background_task_runner), |
| 188 cryptohome_client_(cryptohome_client), | 71 cryptohome_client_(cryptohome_client), |
| 189 session_manager_client_(session_manager_client), | 72 session_manager_client_(session_manager_client), |
| 190 account_id_(account_id), | 73 account_id_(account_id), |
| 191 user_policy_key_dir_(user_policy_key_dir), | 74 user_policy_key_dir_(user_policy_key_dir), |
| 192 legacy_cache_dir_(legacy_token_cache_file.DirName()), | |
| 193 legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file, | |
| 194 legacy_policy_cache_file, | |
| 195 background_task_runner)), | |
| 196 legacy_caches_loaded_(false), | |
| 197 policy_key_loaded_(false), | 75 policy_key_loaded_(false), |
| 198 weak_factory_(this) {} | 76 weak_factory_(this) {} |
| 199 | 77 |
| 200 UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {} | 78 UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {} |
| 201 | 79 |
| 202 void UserCloudPolicyStoreChromeOS::Store( | 80 void UserCloudPolicyStoreChromeOS::Store( |
| 203 const em::PolicyFetchResponse& policy) { | 81 const em::PolicyFetchResponse& policy) { |
| 204 // Cancel all pending requests. | 82 // Cancel all pending requests. |
| 205 weak_factory_.InvalidateWeakPtrs(); | 83 weak_factory_.InvalidateWeakPtrs(); |
| 206 std::unique_ptr<em::PolicyFetchResponse> response( | 84 std::unique_ptr<em::PolicyFetchResponse> response( |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 227 // session. That happens when the browser crashes, or right after signin if | 105 // session. That happens when the browser crashes, or right after signin if |
| 228 // the user has flags configured in about:flags. | 106 // the user has flags configured in about:flags. |
| 229 // However, on those paths we must load policy synchronously so that the | 107 // However, on those paths we must load policy synchronously so that the |
| 230 // Profile initialization never sees unmanaged prefs, which would lead to | 108 // Profile initialization never sees unmanaged prefs, which would lead to |
| 231 // data loss. http://crbug.com/263061 | 109 // data loss. http://crbug.com/263061 |
| 232 std::string policy_blob = | 110 std::string policy_blob = |
| 233 session_manager_client_->BlockingRetrievePolicyForUser( | 111 session_manager_client_->BlockingRetrievePolicyForUser( |
| 234 cryptohome::Identification(account_id_)); | 112 cryptohome::Identification(account_id_)); |
| 235 if (policy_blob.empty()) { | 113 if (policy_blob.empty()) { |
| 236 // The session manager doesn't have policy, or the call failed. | 114 // The session manager doesn't have policy, or the call failed. |
| 237 // Just notify that the load is done, and don't bother with the legacy | |
| 238 // caches in this case. | |
| 239 NotifyStoreLoaded(); | 115 NotifyStoreLoaded(); |
| 240 return; | 116 return; |
| 241 } | 117 } |
| 242 | 118 |
| 243 std::unique_ptr<em::PolicyFetchResponse> policy( | 119 std::unique_ptr<em::PolicyFetchResponse> policy( |
| 244 new em::PolicyFetchResponse()); | 120 new em::PolicyFetchResponse()); |
| 245 if (!policy->ParseFromString(policy_blob)) { | 121 if (!policy->ParseFromString(policy_blob)) { |
| 246 status_ = STATUS_PARSE_ERROR; | 122 status_ = STATUS_PARSE_ERROR; |
| 247 NotifyStoreError(); | 123 NotifyStoreError(); |
| 248 return; | 124 return; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 328 // the session manager. An additional validation is performed after the | 204 // the session manager. An additional validation is performed after the |
| 329 // load; reload the key for that validation too, in case it was rotated. | 205 // load; reload the key for that validation too, in case it was rotated. |
| 330 ReloadPolicyKey(base::Bind(&UserCloudPolicyStoreChromeOS::Load, | 206 ReloadPolicyKey(base::Bind(&UserCloudPolicyStoreChromeOS::Load, |
| 331 weak_factory_.GetWeakPtr())); | 207 weak_factory_.GetWeakPtr())); |
| 332 } | 208 } |
| 333 } | 209 } |
| 334 | 210 |
| 335 void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved( | 211 void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved( |
| 336 const std::string& policy_blob) { | 212 const std::string& policy_blob) { |
| 337 if (policy_blob.empty()) { | 213 if (policy_blob.empty()) { |
| 338 // Policy fetch failed. Try legacy caches if we haven't done that already. | 214 // session_manager doesn't have policy. Adjust internal state and notify |
| 339 if (!legacy_caches_loaded_ && legacy_loader_.get()) { | 215 // the world about the policy update. |
| 340 legacy_caches_loaded_ = true; | 216 policy_.reset(); |
| 341 legacy_loader_->Load( | 217 NotifyStoreLoaded(); |
| 342 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished, | |
| 343 weak_factory_.GetWeakPtr())); | |
| 344 } else { | |
| 345 // session_manager doesn't have policy. Adjust internal state and notify | |
| 346 // the world about the policy update. | |
| 347 policy_.reset(); | |
| 348 NotifyStoreLoaded(); | |
| 349 } | |
| 350 return; | 218 return; |
| 351 } | 219 } |
| 352 | 220 |
| 353 // Policy is supplied by session_manager. Disregard legacy data from now on. | |
| 354 legacy_loader_.reset(); | |
| 355 | |
| 356 std::unique_ptr<em::PolicyFetchResponse> policy( | 221 std::unique_ptr<em::PolicyFetchResponse> policy( |
| 357 new em::PolicyFetchResponse()); | 222 new em::PolicyFetchResponse()); |
| 358 if (!policy->ParseFromString(policy_blob)) { | 223 if (!policy->ParseFromString(policy_blob)) { |
| 359 status_ = STATUS_PARSE_ERROR; | 224 status_ = STATUS_PARSE_ERROR; |
| 360 NotifyStoreError(); | 225 NotifyStoreError(); |
| 361 return; | 226 return; |
| 362 } | 227 } |
| 363 | 228 |
| 364 // Load |policy_key_| to verify the loaded policy. | 229 // Load |policy_key_| to verify the loaded policy. |
| 365 EnsurePolicyKeyLoaded( | 230 EnsurePolicyKeyLoaded( |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 392 if (!validator->success()) { | 257 if (!validator->success()) { |
| 393 status_ = STATUS_VALIDATION_ERROR; | 258 status_ = STATUS_VALIDATION_ERROR; |
| 394 NotifyStoreError(); | 259 NotifyStoreError(); |
| 395 return; | 260 return; |
| 396 } | 261 } |
| 397 | 262 |
| 398 InstallPolicy(std::move(validator->policy_data()), | 263 InstallPolicy(std::move(validator->policy_data()), |
| 399 std::move(validator->payload())); | 264 std::move(validator->payload())); |
| 400 status_ = STATUS_OK; | 265 status_ = STATUS_OK; |
| 401 | 266 |
| 402 // Policy has been loaded successfully. This indicates that new-style policy | |
| 403 // is working, so the legacy cache directory can be removed. | |
| 404 if (!legacy_cache_dir_.empty()) { | |
| 405 background_task_runner()->PostTask( | |
| 406 FROM_HERE, | |
| 407 base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir, | |
| 408 legacy_cache_dir_)); | |
| 409 legacy_cache_dir_.clear(); | |
| 410 } | |
| 411 NotifyStoreLoaded(); | 267 NotifyStoreLoaded(); |
| 412 } | 268 } |
| 413 | 269 |
| 414 void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished( | |
| 415 const std::string& dm_token, | |
| 416 const std::string& device_id, | |
| 417 Status status, | |
| 418 std::unique_ptr<em::PolicyFetchResponse> policy) { | |
| 419 status_ = status; | |
| 420 if (policy.get()) { | |
| 421 // Create and configure a validator for the loaded legacy policy. Note that | |
| 422 // the signature on this policy is not verified. | |
| 423 std::unique_ptr<UserCloudPolicyValidator> validator = CreateValidator( | |
| 424 std::move(policy), CloudPolicyValidatorBase::TIMESTAMP_FULLY_VALIDATED); | |
| 425 validator->ValidateUsername(account_id_.GetUserEmail(), true); | |
| 426 validator.release()->StartValidation( | |
| 427 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated, | |
| 428 weak_factory_.GetWeakPtr(), | |
| 429 dm_token, | |
| 430 device_id)); | |
| 431 } else { | |
| 432 InstallLegacyTokens(dm_token, device_id); | |
| 433 } | |
| 434 } | |
| 435 | |
| 436 void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated( | |
| 437 const std::string& dm_token, | |
| 438 const std::string& device_id, | |
| 439 UserCloudPolicyValidator* validator) { | |
| 440 validation_status_ = validator->status(); | |
| 441 if (validator->success()) { | |
| 442 status_ = STATUS_OK; | |
| 443 InstallPolicy(std::move(validator->policy_data()), | |
| 444 std::move(validator->payload())); | |
| 445 | |
| 446 // Clear the public key version. The public key version field would | |
| 447 // otherwise indicate that we have key installed in the store when in fact | |
| 448 // we haven't. This may result in policy updates failing signature | |
| 449 // verification. | |
| 450 policy_->clear_public_key_version(); | |
| 451 } else { | |
| 452 status_ = STATUS_VALIDATION_ERROR; | |
| 453 } | |
| 454 | |
| 455 InstallLegacyTokens(dm_token, device_id); | |
| 456 } | |
| 457 | |
| 458 void UserCloudPolicyStoreChromeOS::InstallLegacyTokens( | |
| 459 const std::string& dm_token, | |
| 460 const std::string& device_id) { | |
| 461 // Write token and device ID to |policy_|, giving them precedence over the | |
| 462 // policy blob. This is to match the legacy behavior, which used token and | |
| 463 // device id exclusively from the token cache file. | |
| 464 if (!dm_token.empty() && !device_id.empty()) { | |
| 465 if (!policy_.get()) | |
| 466 policy_.reset(new em::PolicyData()); | |
| 467 policy_->set_request_token(dm_token); | |
| 468 policy_->set_device_id(device_id); | |
| 469 } | |
| 470 | |
| 471 // Tell the rest of the world that the policy load completed. | |
| 472 NotifyStoreLoaded(); | |
| 473 } | |
| 474 | |
| 475 // static | |
| 476 void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir( | |
| 477 const base::FilePath& dir) { | |
| 478 if (base::PathExists(dir) && !base::DeleteFile(dir, true)) | |
| 479 LOG(ERROR) << "Failed to remove cache dir " << dir.value(); | |
| 480 } | |
| 481 | |
| 482 void UserCloudPolicyStoreChromeOS::ReloadPolicyKey( | 270 void UserCloudPolicyStoreChromeOS::ReloadPolicyKey( |
| 483 const base::Closure& callback) { | 271 const base::Closure& callback) { |
| 484 std::string* key = new std::string(); | 272 std::string* key = new std::string(); |
| 485 background_task_runner()->PostTaskAndReply( | 273 background_task_runner()->PostTaskAndReply( |
| 486 FROM_HERE, | 274 FROM_HERE, |
| 487 base::Bind(&UserCloudPolicyStoreChromeOS::LoadPolicyKey, | 275 base::Bind(&UserCloudPolicyStoreChromeOS::LoadPolicyKey, |
| 488 policy_key_path_, | 276 policy_key_path_, |
| 489 key), | 277 key), |
| 490 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded, | 278 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded, |
| 491 weak_factory_.GetWeakPtr(), | 279 weak_factory_.GetWeakPtr(), |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 560 | 348 |
| 561 std::unique_ptr<UserCloudPolicyValidator> | 349 std::unique_ptr<UserCloudPolicyValidator> |
| 562 UserCloudPolicyStoreChromeOS::CreateValidatorForLoad( | 350 UserCloudPolicyStoreChromeOS::CreateValidatorForLoad( |
| 563 std::unique_ptr<em::PolicyFetchResponse> policy) { | 351 std::unique_ptr<em::PolicyFetchResponse> policy) { |
| 564 std::unique_ptr<UserCloudPolicyValidator> validator = CreateValidator( | 352 std::unique_ptr<UserCloudPolicyValidator> validator = CreateValidator( |
| 565 std::move(policy), CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE); | 353 std::move(policy), CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE); |
| 566 validator->ValidateUsername(account_id_.GetUserEmail(), true); | 354 validator->ValidateUsername(account_id_.GetUserEmail(), true); |
| 567 const bool allow_rotation = false; | 355 const bool allow_rotation = false; |
| 568 const std::string empty_key = std::string(); | 356 const std::string empty_key = std::string(); |
| 569 // The policy loaded from session manager need not be validated using the | 357 // The policy loaded from session manager need not be validated using the |
| 570 // verification key since it is secure, and since there may be legacy policy | 358 // verification key since it is secure. Hence passing an empty value for the |
| 571 // data that was stored without a verification key. Hence passing an empty | 359 // verification key. |
|
Andrew T Wilson (Slow)
2016/11/08 15:50:40
Actually, the "legacy policy" described in this co
| |
| 572 // value for the verification key. | |
| 573 validator->ValidateSignature(policy_key_, empty_key, | 360 validator->ValidateSignature(policy_key_, empty_key, |
| 574 ExtractDomain(account_id_.GetUserEmail()), | 361 ExtractDomain(account_id_.GetUserEmail()), |
| 575 allow_rotation); | 362 allow_rotation); |
| 576 return validator; | 363 return validator; |
| 577 } | 364 } |
| 578 } // namespace policy | 365 } // namespace policy |
| OLD | NEW |