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.
5 #include "chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/files/file_util.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/stl_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "chrome/browser/chromeos/policy/user_policy_disk_cache.h"
18 #include "chrome/browser/chromeos/policy/user_policy_token_loader.h"
19 #include "chromeos/dbus/cryptohome_client.h"
20 #include "chromeos/dbus/session_manager_client.h"
21 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
22 #include "google_apis/gaia/gaia_auth_util.h"
23 #include "policy/proto/cloud_policy.pb.h"
24 #include "policy/proto/device_management_local.pb.h"
26 namespace em
= enterprise_management
;
32 // Path within |user_policy_key_dir_| that contains the policy key.
33 // "%s" must be substituted with the sanitized username.
34 const base::FilePath::CharType kPolicyKeyFile
[] =
35 FILE_PATH_LITERAL("%s/policy.pub");
37 // Maximum key size that will be loaded, in bytes.
38 const size_t kKeySizeLimit
= 16 * 1024;
40 enum ValidationFailure
{
41 VALIDATION_FAILURE_DBUS
,
42 VALIDATION_FAILURE_LOAD_KEY
,
43 VALIDATION_FAILURE_SIZE
,
46 void SampleValidationFailure(ValidationFailure sample
) {
47 UMA_HISTOGRAM_ENUMERATION("Enterprise.UserPolicyValidationFailure",
49 VALIDATION_FAILURE_SIZE
);
52 // Extracts the domain name from the passed username.
53 std::string
ExtractDomain(const std::string
& username
) {
54 return gaia::ExtractDomainName(gaia::CanonicalizeEmail(username
));
59 // Helper class for loading legacy policy caches.
60 class LegacyPolicyCacheLoader
: public UserPolicyTokenLoader::Delegate
,
61 public UserPolicyDiskCache::Delegate
{
63 typedef base::Callback
<void(const std::string
&,
65 CloudPolicyStore::Status
,
66 scoped_ptr
<em::PolicyFetchResponse
>)> Callback
;
68 LegacyPolicyCacheLoader(
69 const base::FilePath
& token_cache_file
,
70 const base::FilePath
& policy_cache_file
,
71 scoped_refptr
<base::SequencedTaskRunner
> background_task_runner
);
72 ~LegacyPolicyCacheLoader() override
;
74 // Starts loading, and reports the result to |callback| when done.
75 void Load(const Callback
& callback
);
77 // UserPolicyTokenLoader::Delegate:
78 void OnTokenLoaded(const std::string
& token
,
79 const std::string
& device_id
) override
;
81 // UserPolicyDiskCache::Delegate:
82 void OnDiskCacheLoaded(UserPolicyDiskCache::LoadResult result
,
83 const em::CachedCloudPolicyResponse
& policy
) override
;
86 // Checks whether the load operations from the legacy caches completed. If so,
87 // fires the appropriate notification.
88 void CheckLoadFinished();
90 // Maps a disk cache LoadResult to a CloudPolicyStore::Status.
91 static CloudPolicyStore::Status
TranslateLoadResult(
92 UserPolicyDiskCache::LoadResult result
);
94 scoped_refptr
<UserPolicyTokenLoader
> token_loader_
;
95 scoped_refptr
<UserPolicyDiskCache
> policy_cache_
;
97 std::string dm_token_
;
98 std::string device_id_
;
99 scoped_ptr
<em::PolicyFetchResponse
> policy_
;
100 CloudPolicyStore::Status status_
;
104 base::WeakPtrFactory
<LegacyPolicyCacheLoader
> weak_factory_
;
106 DISALLOW_COPY_AND_ASSIGN(LegacyPolicyCacheLoader
);
109 LegacyPolicyCacheLoader::LegacyPolicyCacheLoader(
110 const base::FilePath
& token_cache_file
,
111 const base::FilePath
& policy_cache_file
,
112 scoped_refptr
<base::SequencedTaskRunner
> background_task_runner
)
113 : status_(CloudPolicyStore::STATUS_OK
),
114 weak_factory_(this) {
115 token_loader_
= new UserPolicyTokenLoader(weak_factory_
.GetWeakPtr(),
117 background_task_runner
);
118 policy_cache_
= new UserPolicyDiskCache(weak_factory_
.GetWeakPtr(),
120 background_task_runner
);
123 LegacyPolicyCacheLoader::~LegacyPolicyCacheLoader() {}
125 void LegacyPolicyCacheLoader::Load(const Callback
& callback
) {
126 callback_
= callback
;
127 token_loader_
->Load();
128 policy_cache_
->Load();
131 void LegacyPolicyCacheLoader::OnTokenLoaded(const std::string
& token
,
132 const std::string
& device_id
) {
134 device_id_
= device_id
;
135 token_loader_
= NULL
;
139 void LegacyPolicyCacheLoader::OnDiskCacheLoaded(
140 UserPolicyDiskCache::LoadResult result
,
141 const em::CachedCloudPolicyResponse
& policy
) {
142 status_
= TranslateLoadResult(result
);
143 if (result
== UserPolicyDiskCache::LOAD_RESULT_SUCCESS
) {
144 if (policy
.has_cloud_policy())
145 policy_
.reset(new em::PolicyFetchResponse(policy
.cloud_policy()));
147 LOG(WARNING
) << "Failed to load legacy policy cache: " << result
;
149 policy_cache_
= NULL
;
153 void LegacyPolicyCacheLoader::CheckLoadFinished() {
154 if (!token_loader_
.get() && !policy_cache_
.get())
155 callback_
.Run(dm_token_
, device_id_
, status_
, policy_
.Pass());
159 CloudPolicyStore::Status
LegacyPolicyCacheLoader::TranslateLoadResult(
160 UserPolicyDiskCache::LoadResult result
) {
162 case UserPolicyDiskCache::LOAD_RESULT_SUCCESS
:
163 case UserPolicyDiskCache::LOAD_RESULT_NOT_FOUND
:
164 return CloudPolicyStore::STATUS_OK
;
165 case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR
:
166 case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR
:
167 return CloudPolicyStore::STATUS_LOAD_ERROR
;
170 return CloudPolicyStore::STATUS_OK
;
173 UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
174 chromeos::CryptohomeClient
* cryptohome_client
,
175 chromeos::SessionManagerClient
* session_manager_client
,
176 scoped_refptr
<base::SequencedTaskRunner
> background_task_runner
,
177 const std::string
& username
,
178 const base::FilePath
& user_policy_key_dir
,
179 const base::FilePath
& legacy_token_cache_file
,
180 const base::FilePath
& legacy_policy_cache_file
)
181 : UserCloudPolicyStoreBase(background_task_runner
),
182 cryptohome_client_(cryptohome_client
),
183 session_manager_client_(session_manager_client
),
185 user_policy_key_dir_(user_policy_key_dir
),
186 legacy_cache_dir_(legacy_token_cache_file
.DirName()),
187 legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file
,
188 legacy_policy_cache_file
,
189 background_task_runner
)),
190 legacy_caches_loaded_(false),
191 policy_key_loaded_(false),
192 weak_factory_(this) {}
194 UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {}
196 void UserCloudPolicyStoreChromeOS::Store(
197 const em::PolicyFetchResponse
& policy
) {
198 // Cancel all pending requests.
199 weak_factory_
.InvalidateWeakPtrs();
200 scoped_ptr
<em::PolicyFetchResponse
> response(
201 new em::PolicyFetchResponse(policy
));
202 EnsurePolicyKeyLoaded(
203 base::Bind(&UserCloudPolicyStoreChromeOS::ValidatePolicyForStore
,
204 weak_factory_
.GetWeakPtr(),
205 base::Passed(&response
)));
208 void UserCloudPolicyStoreChromeOS::Load() {
209 // Cancel all pending requests.
210 weak_factory_
.InvalidateWeakPtrs();
211 session_manager_client_
->RetrievePolicyForUser(
213 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyRetrieved
,
214 weak_factory_
.GetWeakPtr()));
217 void UserCloudPolicyStoreChromeOS::LoadImmediately() {
218 // This blocking DBus call is in the startup path and will block the UI
219 // thread. This only happens when the Profile is created synchronously, which
220 // on ChromeOS happens whenever the browser is restarted into the same
221 // session. That happens when the browser crashes, or right after signin if
222 // the user has flags configured in about:flags.
223 // However, on those paths we must load policy synchronously so that the
224 // Profile initialization never sees unmanaged prefs, which would lead to
225 // data loss. http://crbug.com/263061
226 std::string policy_blob
=
227 session_manager_client_
->BlockingRetrievePolicyForUser(username_
);
228 if (policy_blob
.empty()) {
229 // The session manager doesn't have policy, or the call failed.
230 // Just notify that the load is done, and don't bother with the legacy
231 // caches in this case.
236 scoped_ptr
<em::PolicyFetchResponse
> policy(new em::PolicyFetchResponse());
237 if (!policy
->ParseFromString(policy_blob
)) {
238 status_
= STATUS_PARSE_ERROR
;
243 std::string sanitized_username
=
244 cryptohome_client_
->BlockingGetSanitizedUsername(username_
);
245 if (sanitized_username
.empty()) {
246 status_
= STATUS_LOAD_ERROR
;
251 policy_key_path_
= user_policy_key_dir_
.Append(
252 base::StringPrintf(kPolicyKeyFile
, sanitized_username
.c_str()));
253 LoadPolicyKey(policy_key_path_
, &policy_key_
);
254 policy_key_loaded_
= true;
256 scoped_ptr
<UserCloudPolicyValidator
> validator
=
257 CreateValidatorForLoad(policy
.Pass());
258 validator
->RunValidation();
259 OnRetrievedPolicyValidated(validator
.get());
262 void UserCloudPolicyStoreChromeOS::ValidatePolicyForStore(
263 scoped_ptr
<em::PolicyFetchResponse
> policy
) {
264 // Create and configure a validator.
265 scoped_ptr
<UserCloudPolicyValidator
> validator
=
266 CreateValidator(policy
.Pass(),
267 CloudPolicyValidatorBase::TIMESTAMP_REQUIRED
);
268 validator
->ValidateUsername(username_
, true);
269 if (policy_key_
.empty()) {
270 validator
->ValidateInitialKey(GetPolicyVerificationKey(),
271 ExtractDomain(username_
));
273 const bool allow_rotation
= true;
274 validator
->ValidateSignature(policy_key_
,
275 GetPolicyVerificationKey(),
276 ExtractDomain(username_
),
280 // Start validation. The Validator will delete itself once validation is
282 validator
.release()->StartValidation(
283 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated
,
284 weak_factory_
.GetWeakPtr()));
287 void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
288 UserCloudPolicyValidator
* validator
) {
289 validation_status_
= validator
->status();
291 UMA_HISTOGRAM_ENUMERATION(
292 "Enterprise.UserPolicyValidationStoreStatus",
294 UserCloudPolicyValidator::VALIDATION_STATUS_SIZE
);
296 if (!validator
->success()) {
297 status_
= STATUS_VALIDATION_ERROR
;
302 std::string policy_blob
;
303 if (!validator
->policy()->SerializeToString(&policy_blob
)) {
304 status_
= STATUS_SERIALIZE_ERROR
;
309 session_manager_client_
->StorePolicyForUser(
312 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored
,
313 weak_factory_
.GetWeakPtr()));
316 void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success
) {
318 status_
= STATUS_STORE_ERROR
;
321 // Load the policy right after storing it, to make sure it was accepted by
322 // the session manager. An additional validation is performed after the
323 // load; reload the key for that validation too, in case it was rotated.
324 ReloadPolicyKey(base::Bind(&UserCloudPolicyStoreChromeOS::Load
,
325 weak_factory_
.GetWeakPtr()));
329 void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
330 const std::string
& policy_blob
) {
331 if (policy_blob
.empty()) {
332 // Policy fetch failed. Try legacy caches if we haven't done that already.
333 if (!legacy_caches_loaded_
&& legacy_loader_
.get()) {
334 legacy_caches_loaded_
= true;
335 legacy_loader_
->Load(
336 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished
,
337 weak_factory_
.GetWeakPtr()));
339 // session_manager doesn't have policy. Adjust internal state and notify
340 // the world about the policy update.
347 // Policy is supplied by session_manager. Disregard legacy data from now on.
348 legacy_loader_
.reset();
350 scoped_ptr
<em::PolicyFetchResponse
> policy(new em::PolicyFetchResponse());
351 if (!policy
->ParseFromString(policy_blob
)) {
352 status_
= STATUS_PARSE_ERROR
;
357 // Load |policy_key_| to verify the loaded policy.
358 EnsurePolicyKeyLoaded(
359 base::Bind(&UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy
,
360 weak_factory_
.GetWeakPtr(),
361 base::Passed(&policy
)));
364 void UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy(
365 scoped_ptr
<em::PolicyFetchResponse
> policy
) {
366 // Create and configure a validator for the loaded policy.
367 scoped_ptr
<UserCloudPolicyValidator
> validator
=
368 CreateValidatorForLoad(policy
.Pass());
369 // Start validation. The Validator will delete itself once validation is
371 validator
.release()->StartValidation(
372 base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated
,
373 weak_factory_
.GetWeakPtr()));
376 void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
377 UserCloudPolicyValidator
* validator
) {
378 validation_status_
= validator
->status();
380 UMA_HISTOGRAM_ENUMERATION(
381 "Enterprise.UserPolicyValidationLoadStatus",
383 UserCloudPolicyValidator::VALIDATION_STATUS_SIZE
);
385 if (!validator
->success()) {
386 status_
= STATUS_VALIDATION_ERROR
;
391 InstallPolicy(validator
->policy_data().Pass(), validator
->payload().Pass());
394 // Policy has been loaded successfully. This indicates that new-style policy
395 // is working, so the legacy cache directory can be removed.
396 if (!legacy_cache_dir_
.empty()) {
397 background_task_runner()->PostTask(
399 base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir
,
401 legacy_cache_dir_
.clear();
406 void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished(
407 const std::string
& dm_token
,
408 const std::string
& device_id
,
410 scoped_ptr
<em::PolicyFetchResponse
> policy
) {
413 // Create and configure a validator for the loaded legacy policy. Note that
414 // the signature on this policy is not verified.
415 scoped_ptr
<UserCloudPolicyValidator
> validator
=
416 CreateValidator(policy
.Pass(),
417 CloudPolicyValidatorBase::TIMESTAMP_REQUIRED
);
418 validator
->ValidateUsername(username_
, true);
419 validator
.release()->StartValidation(
420 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated
,
421 weak_factory_
.GetWeakPtr(),
425 InstallLegacyTokens(dm_token
, device_id
);
429 void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated(
430 const std::string
& dm_token
,
431 const std::string
& device_id
,
432 UserCloudPolicyValidator
* validator
) {
433 validation_status_
= validator
->status();
434 if (validator
->success()) {
436 InstallPolicy(validator
->policy_data().Pass(), validator
->payload().Pass());
438 // Clear the public key version. The public key version field would
439 // otherwise indicate that we have key installed in the store when in fact
440 // we haven't. This may result in policy updates failing signature
442 policy_
->clear_public_key_version();
444 status_
= STATUS_VALIDATION_ERROR
;
447 InstallLegacyTokens(dm_token
, device_id
);
450 void UserCloudPolicyStoreChromeOS::InstallLegacyTokens(
451 const std::string
& dm_token
,
452 const std::string
& device_id
) {
453 // Write token and device ID to |policy_|, giving them precedence over the
454 // policy blob. This is to match the legacy behavior, which used token and
455 // device id exclusively from the token cache file.
456 if (!dm_token
.empty() && !device_id
.empty()) {
458 policy_
.reset(new em::PolicyData());
459 policy_
->set_request_token(dm_token
);
460 policy_
->set_device_id(device_id
);
463 // Tell the rest of the world that the policy load completed.
468 void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(
469 const base::FilePath
& dir
) {
470 if (base::PathExists(dir
) && !base::DeleteFile(dir
, true))
471 LOG(ERROR
) << "Failed to remove cache dir " << dir
.value();
474 void UserCloudPolicyStoreChromeOS::ReloadPolicyKey(
475 const base::Closure
& callback
) {
476 std::string
* key
= new std::string();
477 background_task_runner()->PostTaskAndReply(
479 base::Bind(&UserCloudPolicyStoreChromeOS::LoadPolicyKey
,
482 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded
,
483 weak_factory_
.GetWeakPtr(),
489 void UserCloudPolicyStoreChromeOS::LoadPolicyKey(const base::FilePath
& path
,
491 if (!base::PathExists(path
)) {
492 // There is no policy key the first time that a user fetches policy. If
493 // |path| does not exist then that is the most likely scenario, so there's
494 // no need to sample a failure.
495 VLOG(1) << "No key at " << path
.value();
499 const bool read_success
= base::ReadFileToString(path
, key
, kKeySizeLimit
);
500 // If the read was successful and the file size is 0 or if the read fails
501 // due to file size exceeding |kKeySizeLimit|, log error.
502 if ((read_success
&& key
->length() == 0) ||
503 (!read_success
&& key
->length() == kKeySizeLimit
)) {
504 LOG(ERROR
) << "Key at " << path
.value()
505 << (read_success
? " is empty." : " exceeds size limit");
507 } else if (!read_success
) {
508 LOG(ERROR
) << "Failed to read key at " << path
.value();
512 SampleValidationFailure(VALIDATION_FAILURE_LOAD_KEY
);
515 void UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded(
517 const base::Closure
& callback
) {
519 policy_key_loaded_
= true;
523 void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded(
524 const base::Closure
& callback
) {
525 if (policy_key_loaded_
) {
528 // Get the hashed username that's part of the key's path, to determine
529 // |policy_key_path_|.
530 cryptohome_client_
->GetSanitizedUsername(username_
,
531 base::Bind(&UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername
,
532 weak_factory_
.GetWeakPtr(),
537 void UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername(
538 const base::Closure
& callback
,
539 chromeos::DBusMethodCallStatus call_status
,
540 const std::string
& sanitized_username
) {
541 // The default empty path will always yield an empty key.
542 if (call_status
== chromeos::DBUS_METHOD_CALL_SUCCESS
&&
543 !sanitized_username
.empty()) {
544 policy_key_path_
= user_policy_key_dir_
.Append(
545 base::StringPrintf(kPolicyKeyFile
, sanitized_username
.c_str()));
547 SampleValidationFailure(VALIDATION_FAILURE_DBUS
);
549 ReloadPolicyKey(callback
);
552 scoped_ptr
<UserCloudPolicyValidator
>
553 UserCloudPolicyStoreChromeOS::CreateValidatorForLoad(
554 scoped_ptr
<em::PolicyFetchResponse
> policy
) {
555 scoped_ptr
<UserCloudPolicyValidator
> validator
= CreateValidator(
556 policy
.Pass(), CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE
);
557 validator
->ValidateUsername(username_
, true);
558 const bool allow_rotation
= false;
559 const std::string empty_key
= std::string();
560 // The policy loaded from session manager need not be validated using the
561 // verification key since it is secure, and since there may be legacy policy
562 // data that was stored without a verification key. Hence passing an empty
563 // value for the verification key.
564 validator
->ValidateSignature(
565 policy_key_
, empty_key
, ExtractDomain(username_
), allow_rotation
);
566 return validator
.Pass();
568 } // namespace policy