Home | History | Annotate | Download | only in policy
      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
    572