Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / policy / user_cloud_policy_store_chromeos.cc
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/user_cloud_policy_store_chromeos.h"
6
7 #include "base/bind.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"
25
26 namespace em = enterprise_management;
27
28 namespace policy {
29
30 namespace {
31
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");
36
37 // Maximum key size that will be loaded, in bytes.
38 const size_t kKeySizeLimit = 16 * 1024;
39
40 enum ValidationFailure {
41   VALIDATION_FAILURE_DBUS,
42   VALIDATION_FAILURE_LOAD_KEY,
43   VALIDATION_FAILURE_SIZE,
44 };
45
46 void SampleValidationFailure(ValidationFailure sample) {
47   UMA_HISTOGRAM_ENUMERATION("Enterprise.UserPolicyValidationFailure",
48                             sample,
49                             VALIDATION_FAILURE_SIZE);
50 }
51
52 // Extracts the domain name from the passed username.
53 std::string ExtractDomain(const std::string& username) {
54   return gaia::ExtractDomainName(gaia::CanonicalizeEmail(username));
55 }
56
57 }  // namespace
58
59 // Helper class for loading legacy policy caches.
60 class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate,
61                                 public UserPolicyDiskCache::Delegate {
62  public:
63   typedef base::Callback<void(const std::string&,
64                               const std::string&,
65                               CloudPolicyStore::Status,
66                               scoped_ptr<em::PolicyFetchResponse>)> Callback;
67
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   virtual ~LegacyPolicyCacheLoader();
73
74   // Starts loading, and reports the result to |callback| when done.
75   void Load(const Callback& callback);
76
77   // UserPolicyTokenLoader::Delegate:
78   virtual void OnTokenLoaded(const std::string& token,
79                              const std::string& device_id) OVERRIDE;
80
81   // UserPolicyDiskCache::Delegate:
82   virtual void OnDiskCacheLoaded(
83       UserPolicyDiskCache::LoadResult result,
84       const em::CachedCloudPolicyResponse& policy) OVERRIDE;
85
86  private:
87   // Checks whether the load operations from the legacy caches completed. If so,
88   // fires the appropriate notification.
89   void CheckLoadFinished();
90
91   // Maps a disk cache LoadResult to a CloudPolicyStore::Status.
92   static CloudPolicyStore::Status TranslateLoadResult(
93       UserPolicyDiskCache::LoadResult result);
94
95   scoped_refptr<UserPolicyTokenLoader> token_loader_;
96   scoped_refptr<UserPolicyDiskCache> policy_cache_;
97
98   std::string dm_token_;
99   std::string device_id_;
100   bool has_policy_;
101   scoped_ptr<em::PolicyFetchResponse> policy_;
102   CloudPolicyStore::Status status_;
103
104   Callback callback_;
105
106   base::WeakPtrFactory<LegacyPolicyCacheLoader> weak_factory_;
107
108   DISALLOW_COPY_AND_ASSIGN(LegacyPolicyCacheLoader);
109 };
110
111 LegacyPolicyCacheLoader::LegacyPolicyCacheLoader(
112     const base::FilePath& token_cache_file,
113     const base::FilePath& policy_cache_file,
114     scoped_refptr<base::SequencedTaskRunner> background_task_runner)
115     : has_policy_(false),
116       status_(CloudPolicyStore::STATUS_OK),
117       weak_factory_(this) {
118   token_loader_ = new UserPolicyTokenLoader(weak_factory_.GetWeakPtr(),
119                                             token_cache_file,
120                                             background_task_runner);
121   policy_cache_ = new UserPolicyDiskCache(weak_factory_.GetWeakPtr(),
122                                           policy_cache_file,
123                                           background_task_runner);
124 }
125
126 LegacyPolicyCacheLoader::~LegacyPolicyCacheLoader() {}
127
128 void LegacyPolicyCacheLoader::Load(const Callback& callback) {
129   callback_ = callback;
130   token_loader_->Load();
131   policy_cache_->Load();
132 }
133
134 void LegacyPolicyCacheLoader::OnTokenLoaded(const std::string& token,
135                                             const std::string& device_id) {
136   dm_token_ = token;
137   device_id_ = device_id;
138   token_loader_ = NULL;
139   CheckLoadFinished();
140 }
141
142 void LegacyPolicyCacheLoader::OnDiskCacheLoaded(
143     UserPolicyDiskCache::LoadResult result,
144     const em::CachedCloudPolicyResponse& policy) {
145   status_ = TranslateLoadResult(result);
146   if (result == UserPolicyDiskCache::LOAD_RESULT_SUCCESS) {
147     if (policy.has_cloud_policy())
148       policy_.reset(new em::PolicyFetchResponse(policy.cloud_policy()));
149   } else {
150     LOG(WARNING) << "Failed to load legacy policy cache: " << result;
151   }
152   policy_cache_ = NULL;
153   CheckLoadFinished();
154 }
155
156 void LegacyPolicyCacheLoader::CheckLoadFinished() {
157   if (!token_loader_.get() && !policy_cache_.get())
158     callback_.Run(dm_token_, device_id_, status_, policy_.Pass());
159 }
160
161 // static
162 CloudPolicyStore::Status LegacyPolicyCacheLoader::TranslateLoadResult(
163     UserPolicyDiskCache::LoadResult result) {
164   switch (result) {
165     case UserPolicyDiskCache::LOAD_RESULT_SUCCESS:
166     case UserPolicyDiskCache::LOAD_RESULT_NOT_FOUND:
167       return CloudPolicyStore::STATUS_OK;
168     case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR:
169     case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR:
170       return CloudPolicyStore::STATUS_LOAD_ERROR;
171   }
172   NOTREACHED();
173   return CloudPolicyStore::STATUS_OK;
174 }
175
176 UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
177     chromeos::CryptohomeClient* cryptohome_client,
178     chromeos::SessionManagerClient* session_manager_client,
179     scoped_refptr<base::SequencedTaskRunner> background_task_runner,
180     const std::string& username,
181     const base::FilePath& user_policy_key_dir,
182     const base::FilePath& legacy_token_cache_file,
183     const base::FilePath& legacy_policy_cache_file)
184     : UserCloudPolicyStoreBase(background_task_runner),
185       cryptohome_client_(cryptohome_client),
186       session_manager_client_(session_manager_client),
187       username_(username),
188       user_policy_key_dir_(user_policy_key_dir),
189       legacy_cache_dir_(legacy_token_cache_file.DirName()),
190       legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file,
191                                                  legacy_policy_cache_file,
192                                                  background_task_runner)),
193       legacy_caches_loaded_(false),
194       policy_key_loaded_(false),
195       weak_factory_(this) {}
196
197 UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {}
198
199 void UserCloudPolicyStoreChromeOS::Store(
200     const em::PolicyFetchResponse& policy) {
201   // Cancel all pending requests.
202   weak_factory_.InvalidateWeakPtrs();
203   scoped_ptr<em::PolicyFetchResponse> response(
204       new em::PolicyFetchResponse(policy));
205   EnsurePolicyKeyLoaded(
206       base::Bind(&UserCloudPolicyStoreChromeOS::ValidatePolicyForStore,
207                  weak_factory_.GetWeakPtr(),
208                  base::Passed(&response)));
209 }
210
211 void UserCloudPolicyStoreChromeOS::Load() {
212   // Cancel all pending requests.
213   weak_factory_.InvalidateWeakPtrs();
214   session_manager_client_->RetrievePolicyForUser(
215       username_,
216       base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyRetrieved,
217                  weak_factory_.GetWeakPtr()));
218 }
219
220 void UserCloudPolicyStoreChromeOS::LoadImmediately() {
221   // This blocking DBus call is in the startup path and will block the UI
222   // thread. This only happens when the Profile is created synchronously, which
223   // on ChromeOS happens whenever the browser is restarted into the same
224   // session. That happens when the browser crashes, or right after signin if
225   // the user has flags configured in about:flags.
226   // However, on those paths we must load policy synchronously so that the
227   // Profile initialization never sees unmanaged prefs, which would lead to
228   // data loss. http://crbug.com/263061
229   std::string policy_blob =
230       session_manager_client_->BlockingRetrievePolicyForUser(username_);
231   if (policy_blob.empty()) {
232     // The session manager doesn't have policy, or the call failed.
233     // Just notify that the load is done, and don't bother with the legacy
234     // caches in this case.
235     NotifyStoreLoaded();
236     return;
237   }
238
239   scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
240   if (!policy->ParseFromString(policy_blob)) {
241     status_ = STATUS_PARSE_ERROR;
242     NotifyStoreError();
243     return;
244   }
245
246   std::string sanitized_username =
247       cryptohome_client_->BlockingGetSanitizedUsername(username_);
248   if (sanitized_username.empty()) {
249     status_ = STATUS_LOAD_ERROR;
250     NotifyStoreError();
251     return;
252   }
253
254   policy_key_path_ = user_policy_key_dir_.Append(
255       base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
256   LoadPolicyKey(policy_key_path_, &policy_key_);
257   policy_key_loaded_ = true;
258
259   scoped_ptr<UserCloudPolicyValidator> validator =
260       CreateValidatorForLoad(policy.Pass());
261   validator->RunValidation();
262   OnRetrievedPolicyValidated(validator.get());
263 }
264
265 void UserCloudPolicyStoreChromeOS::ValidatePolicyForStore(
266     scoped_ptr<em::PolicyFetchResponse> policy) {
267   // Create and configure a validator.
268   scoped_ptr<UserCloudPolicyValidator> validator =
269       CreateValidator(policy.Pass(),
270                       CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
271   validator->ValidateUsername(username_, true);
272   if (policy_key_.empty()) {
273     validator->ValidateInitialKey(GetPolicyVerificationKey(),
274                                   ExtractDomain(username_));
275   } else {
276     const bool allow_rotation = true;
277     validator->ValidateSignature(policy_key_,
278                                  GetPolicyVerificationKey(),
279                                  ExtractDomain(username_),
280                                  allow_rotation);
281   }
282
283   // Start validation. The Validator will delete itself once validation is
284   // complete.
285   validator.release()->StartValidation(
286       base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
287                  weak_factory_.GetWeakPtr()));
288 }
289
290 void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
291     UserCloudPolicyValidator* validator) {
292   validation_status_ = validator->status();
293
294   UMA_HISTOGRAM_ENUMERATION(
295       "Enterprise.UserPolicyValidationStoreStatus",
296       validation_status_,
297       UserCloudPolicyValidator::VALIDATION_STATUS_SIZE);
298
299   if (!validator->success()) {
300     status_ = STATUS_VALIDATION_ERROR;
301     NotifyStoreError();
302     return;
303   }
304
305   std::string policy_blob;
306   if (!validator->policy()->SerializeToString(&policy_blob)) {
307     status_ = STATUS_SERIALIZE_ERROR;
308     NotifyStoreError();
309     return;
310   }
311
312   session_manager_client_->StorePolicyForUser(
313       username_,
314       policy_blob,
315       base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored,
316                  weak_factory_.GetWeakPtr()));
317 }
318
319 void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) {
320   if (!success) {
321     status_ = STATUS_STORE_ERROR;
322     NotifyStoreError();
323   } else {
324     // Load the policy right after storing it, to make sure it was accepted by
325     // the session manager. An additional validation is performed after the
326     // load; reload the key for that validation too, in case it was rotated.
327     ReloadPolicyKey(base::Bind(&UserCloudPolicyStoreChromeOS::Load,
328                                weak_factory_.GetWeakPtr()));
329   }
330 }
331
332 void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
333     const std::string& policy_blob) {
334   if (policy_blob.empty()) {
335     // Policy fetch failed. Try legacy caches if we haven't done that already.
336     if (!legacy_caches_loaded_ && legacy_loader_.get()) {
337       legacy_caches_loaded_ = true;
338       legacy_loader_->Load(
339           base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished,
340                      weak_factory_.GetWeakPtr()));
341     } else {
342       // session_manager doesn't have policy. Adjust internal state and notify
343       // the world about the policy update.
344       policy_.reset();
345       NotifyStoreLoaded();
346     }
347     return;
348   }
349
350   // Policy is supplied by session_manager. Disregard legacy data from now on.
351   legacy_loader_.reset();
352
353   scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
354   if (!policy->ParseFromString(policy_blob)) {
355     status_ = STATUS_PARSE_ERROR;
356     NotifyStoreError();
357     return;
358   }
359
360   // Load |policy_key_| to verify the loaded policy.
361   EnsurePolicyKeyLoaded(
362       base::Bind(&UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy,
363                  weak_factory_.GetWeakPtr(),
364                  base::Passed(&policy)));
365 }
366
367 void UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy(
368     scoped_ptr<em::PolicyFetchResponse> policy) {
369   // Create and configure a validator for the loaded policy.
370   scoped_ptr<UserCloudPolicyValidator> validator =
371       CreateValidatorForLoad(policy.Pass());
372   // Start validation. The Validator will delete itself once validation is
373   // complete.
374   validator.release()->StartValidation(
375       base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated,
376                  weak_factory_.GetWeakPtr()));
377 }
378
379 void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
380     UserCloudPolicyValidator* validator) {
381   validation_status_ = validator->status();
382
383   UMA_HISTOGRAM_ENUMERATION(
384       "Enterprise.UserPolicyValidationLoadStatus",
385       validation_status_,
386       UserCloudPolicyValidator::VALIDATION_STATUS_SIZE);
387
388   if (!validator->success()) {
389     status_ = STATUS_VALIDATION_ERROR;
390     NotifyStoreError();
391     return;
392   }
393
394   InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
395   status_ = STATUS_OK;
396
397   // Policy has been loaded successfully. This indicates that new-style policy
398   // is working, so the legacy cache directory can be removed.
399   if (!legacy_cache_dir_.empty()) {
400     background_task_runner()->PostTask(
401         FROM_HERE,
402         base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir,
403                    legacy_cache_dir_));
404     legacy_cache_dir_.clear();
405   }
406   NotifyStoreLoaded();
407 }
408
409 void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished(
410     const std::string& dm_token,
411     const std::string& device_id,
412     Status status,
413     scoped_ptr<em::PolicyFetchResponse> policy) {
414   status_ = status;
415   if (policy.get()) {
416     // Create and configure a validator for the loaded legacy policy. Note that
417     // the signature on this policy is not verified.
418     scoped_ptr<UserCloudPolicyValidator> validator =
419         CreateValidator(policy.Pass(),
420                         CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
421     validator->ValidateUsername(username_, true);
422     validator.release()->StartValidation(
423         base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated,
424                    weak_factory_.GetWeakPtr(),
425                    dm_token,
426                    device_id));
427   } else {
428     InstallLegacyTokens(dm_token, device_id);
429   }
430 }
431
432 void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated(
433     const std::string& dm_token,
434     const std::string& device_id,
435     UserCloudPolicyValidator* validator) {
436   validation_status_ = validator->status();
437   if (validator->success()) {
438     status_ = STATUS_OK;
439     InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
440
441     // Clear the public key version. The public key version field would
442     // otherwise indicate that we have key installed in the store when in fact
443     // we haven't. This may result in policy updates failing signature
444     // verification.
445     policy_->clear_public_key_version();
446   } else {
447     status_ = STATUS_VALIDATION_ERROR;
448   }
449
450   InstallLegacyTokens(dm_token, device_id);
451 }
452
453 void UserCloudPolicyStoreChromeOS::InstallLegacyTokens(
454     const std::string& dm_token,
455     const std::string& device_id) {
456   // Write token and device ID to |policy_|, giving them precedence over the
457   // policy blob. This is to match the legacy behavior, which used token and
458   // device id exclusively from the token cache file.
459   if (!dm_token.empty() && !device_id.empty()) {
460     if (!policy_.get())
461       policy_.reset(new em::PolicyData());
462     policy_->set_request_token(dm_token);
463     policy_->set_device_id(device_id);
464   }
465
466   // Tell the rest of the world that the policy load completed.
467   NotifyStoreLoaded();
468 }
469
470 // static
471 void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(
472     const base::FilePath& dir) {
473   if (base::PathExists(dir) && !base::DeleteFile(dir, true))
474     LOG(ERROR) << "Failed to remove cache dir " << dir.value();
475 }
476
477 void UserCloudPolicyStoreChromeOS::ReloadPolicyKey(
478     const base::Closure& callback) {
479   std::string* key = new std::string();
480   background_task_runner()->PostTaskAndReply(
481       FROM_HERE,
482       base::Bind(&UserCloudPolicyStoreChromeOS::LoadPolicyKey,
483                  policy_key_path_,
484                  key),
485       base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded,
486                  weak_factory_.GetWeakPtr(),
487                  base::Owned(key),
488                  callback));
489 }
490
491 // static
492 void UserCloudPolicyStoreChromeOS::LoadPolicyKey(const base::FilePath& path,
493                                                  std::string* key) {
494   if (!base::PathExists(path)) {
495     // There is no policy key the first time that a user fetches policy. If
496     // |path| does not exist then that is the most likely scenario, so there's
497     // no need to sample a failure.
498     VLOG(1) << "No key at " << path.value();
499     return;
500   }
501
502   const bool read_success = base::ReadFileToString(path, key, kKeySizeLimit);
503   // If the read was successful and the file size is 0 or if the read fails
504   // due to file size exceeding |kKeySizeLimit|, log error.
505   if ((read_success && key->length() == 0) ||
506       (!read_success && key->length() == kKeySizeLimit)) {
507     LOG(ERROR) << "Key at " << path.value()
508                << (read_success ? " is empty." : " exceeds size limit");
509     key->clear();
510   } else if (!read_success) {
511     LOG(ERROR) << "Failed to read key at " << path.value();
512   }
513
514   if (key->empty())
515     SampleValidationFailure(VALIDATION_FAILURE_LOAD_KEY);
516 }
517
518 void UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded(
519     std::string* key,
520     const base::Closure& callback) {
521   policy_key_ = *key;
522   policy_key_loaded_ = true;
523   callback.Run();
524 }
525
526 void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded(
527     const base::Closure& callback) {
528   if (policy_key_loaded_) {
529     callback.Run();
530   } else {
531     // Get the hashed username that's part of the key's path, to determine
532     // |policy_key_path_|.
533     cryptohome_client_->GetSanitizedUsername(username_,
534         base::Bind(&UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername,
535                    weak_factory_.GetWeakPtr(),
536                    callback));
537   }
538 }
539
540 void UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername(
541     const base::Closure& callback,
542     chromeos::DBusMethodCallStatus call_status,
543     const std::string& sanitized_username) {
544   // The default empty path will always yield an empty key.
545   if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS &&
546       !sanitized_username.empty()) {
547     policy_key_path_ = user_policy_key_dir_.Append(
548         base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
549   } else {
550     SampleValidationFailure(VALIDATION_FAILURE_DBUS);
551   }
552   ReloadPolicyKey(callback);
553 }
554
555 scoped_ptr<UserCloudPolicyValidator>
556 UserCloudPolicyStoreChromeOS::CreateValidatorForLoad(
557     scoped_ptr<em::PolicyFetchResponse> policy) {
558   scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(
559       policy.Pass(), CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE);
560   validator->ValidateUsername(username_, true);
561   const bool allow_rotation = false;
562   const std::string empty_key = std::string();
563   // The policy loaded from session manager need not be validated using the
564   // verification key since it is secure, and since there may be legacy policy
565   // data that was stored without a verification key. Hence passing an empty
566   // value for the verification key.
567   validator->ValidateSignature(
568       policy_key_, empty_key, ExtractDomain(username_), allow_rotation);
569   return validator.Pass();
570 }
571 }  // namespace policy