root/chrome/browser/chromeos/settings/session_manager_operation.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_loading_
  2. Start
  3. RestartLoad
  4. StartLoading
  5. ReportResult
  6. EnsureOwnerKey
  7. LoadOwnerKey
  8. StoreOwnerKey
  9. RetrieveDeviceSettings
  10. ValidateDeviceSettings
  11. ReportValidatorStatus
  12. Run
  13. weak_factory_
  14. Run
  15. HandleStoreResult
  16. weak_factory_
  17. Run
  18. StartSigning
  19. AssembleAndSignPolicy
  20. StoreDeviceSettingsBlob
  21. HandleStoreResult

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/settings/session_manager_operation.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/task_runner_util.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/time/time.h"
#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
#include "chrome/browser/chromeos/settings/owner_key_util.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/rsa_private_key.h"
#include "crypto/signature_creator.h"
#include "policy/proto/device_management_backend.pb.h"

namespace em = enterprise_management;

namespace chromeos {

SessionManagerOperation::SessionManagerOperation(const Callback& callback)
    : session_manager_client_(NULL),
      weak_factory_(this),
      callback_(callback),
      force_key_load_(false),
      is_loading_(false) {}

SessionManagerOperation::~SessionManagerOperation() {}

void SessionManagerOperation::Start(
    SessionManagerClient* session_manager_client,
    scoped_refptr<OwnerKeyUtil> owner_key_util,
    scoped_refptr<OwnerKey> owner_key) {
  session_manager_client_ = session_manager_client;
  owner_key_util_ = owner_key_util;
  owner_key_ = owner_key;
  Run();
}

void SessionManagerOperation::RestartLoad(bool key_changed) {
  if (key_changed)
    owner_key_ = NULL;

  if (!is_loading_)
    return;

  // Abort previous load operations.
  weak_factory_.InvalidateWeakPtrs();
  // Mark as not loading to start loading again.
  is_loading_ = false;
  StartLoading();
}

void SessionManagerOperation::StartLoading() {
  if (is_loading_)
    return;
  is_loading_ = true;
  EnsureOwnerKey(base::Bind(&SessionManagerOperation::RetrieveDeviceSettings,
                            weak_factory_.GetWeakPtr()));
}

void SessionManagerOperation::ReportResult(
    DeviceSettingsService::Status status) {
  callback_.Run(this, status);
}

void SessionManagerOperation::EnsureOwnerKey(const base::Closure& callback) {
  if (force_key_load_ || !owner_key_.get() || !owner_key_->public_key()) {
    scoped_refptr<base::TaskRunner> task_runner =
        content::BrowserThread::GetBlockingPool()->
        GetTaskRunnerWithShutdownBehavior(
            base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
    base::PostTaskAndReplyWithResult(
        task_runner.get(),
        FROM_HERE,
        base::Bind(&SessionManagerOperation::LoadOwnerKey,
                   owner_key_util_, owner_key_),
        base::Bind(&SessionManagerOperation::StoreOwnerKey,
                   weak_factory_.GetWeakPtr(), callback));
  } else {
    callback.Run();
  }
}

// static
scoped_refptr<OwnerKey> SessionManagerOperation::LoadOwnerKey(
    scoped_refptr<OwnerKeyUtil> util,
    scoped_refptr<OwnerKey> current_key) {
  scoped_ptr<std::vector<uint8> > public_key;
  scoped_ptr<crypto::RSAPrivateKey> private_key;

  // Keep any already-existing keys.
  if (current_key.get()) {
    if (current_key->public_key())
      public_key.reset(new std::vector<uint8>(*current_key->public_key()));
    if (current_key->private_key())
      private_key.reset(current_key->private_key()->Copy());
  }

  if (!public_key.get() && util->IsPublicKeyPresent()) {
    public_key.reset(new std::vector<uint8>());
    if (!util->ImportPublicKey(public_key.get()))
      LOG(ERROR) << "Failed to load public owner key.";
  }

  if (public_key.get() && !private_key.get()) {
    private_key.reset(util->FindPrivateKey(*public_key));
    if (!private_key.get())
      VLOG(1) << "Failed to load private owner key.";
  }

  return new OwnerKey(public_key.Pass(), private_key.Pass());
}

void SessionManagerOperation::StoreOwnerKey(const base::Closure& callback,
                                            scoped_refptr<OwnerKey> new_key) {
  force_key_load_ = false;
  owner_key_ = new_key;

  if (!owner_key_.get() || !owner_key_->public_key()) {
    ReportResult(DeviceSettingsService::STORE_KEY_UNAVAILABLE);
    return;
  }

  callback.Run();
}

void SessionManagerOperation::RetrieveDeviceSettings() {
  session_manager_client()->RetrieveDevicePolicy(
      base::Bind(&SessionManagerOperation::ValidateDeviceSettings,
                 weak_factory_.GetWeakPtr()));
}

void SessionManagerOperation::ValidateDeviceSettings(
    const std::string& policy_blob) {
  scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
  if (policy_blob.empty()) {
    ReportResult(DeviceSettingsService::STORE_NO_POLICY);
    return;
  }

  if (!policy->ParseFromString(policy_blob) ||
      !policy->IsInitialized()) {
    ReportResult(DeviceSettingsService::STORE_INVALID_POLICY);
    return;
  }

  base::SequencedWorkerPool* pool =
      content::BrowserThread::GetBlockingPool();
  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
      pool->GetSequencedTaskRunnerWithShutdownBehavior(
          pool->GetSequenceToken(),
          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);

  policy::DeviceCloudPolicyValidator* validator =
      policy::DeviceCloudPolicyValidator::Create(policy.Pass(),
                                                 background_task_runner);


  // Policy auto-generated by session manager doesn't include a timestamp, so
  // the timestamp shouldn't be verified in that case.
  //
  // Additionally, offline devices can get their clock set backwards in time
  // under some hardware conditions; checking the timestamp now could likely
  // find a value in the future, and prevent the user from signing-in or
  // starting guest mode. Tlsdate will eventually fix the clock when the device
  // is back online, but the network configuration may come from device ONC.
  //
  // To prevent all of these issues the timestamp is just not verified when
  // loading the device policy from the cache. Note that the timestamp is still
  // verified during enrollment and when a new policy is fetched from the
  // server.
  validator->ValidateAgainstCurrentPolicy(
      policy_data_.get(),
      policy::CloudPolicyValidatorBase::TIMESTAMP_NOT_REQUIRED,
      policy::CloudPolicyValidatorBase::DM_TOKEN_NOT_REQUIRED);
  validator->ValidatePolicyType(policy::dm_protocol::kChromeDevicePolicyType);
  validator->ValidatePayload();
  // We don't check the DMServer verification key below, because the signing
  // key is validated when it is installed.
  validator->ValidateSignature(owner_key_->public_key_as_string(),
                               std::string(),  // No key validation check.
                               std::string(),
                               false);
  validator->StartValidation(
      base::Bind(&SessionManagerOperation::ReportValidatorStatus,
                 weak_factory_.GetWeakPtr()));
}

void SessionManagerOperation::ReportValidatorStatus(
    policy::DeviceCloudPolicyValidator* validator) {
  DeviceSettingsService::Status status =
      DeviceSettingsService::STORE_VALIDATION_ERROR;
  if (validator->success()) {
    status = DeviceSettingsService::STORE_SUCCESS;
    policy_data_ = validator->policy_data().Pass();
    device_settings_ = validator->payload().Pass();
  } else {
    LOG(ERROR) << "Policy validation failed: " << validator->status();

    // Those are mostly caused by RTC loss and are recoverable.
    if (validator->status() ==
        policy::DeviceCloudPolicyValidator::VALIDATION_BAD_TIMESTAMP) {
      status = DeviceSettingsService::STORE_TEMP_VALIDATION_ERROR;
    }
  }

  ReportResult(status);
}

LoadSettingsOperation::LoadSettingsOperation(const Callback& callback)
    : SessionManagerOperation(callback) {}

LoadSettingsOperation::~LoadSettingsOperation() {}

void LoadSettingsOperation::Run() {
  StartLoading();
}

StoreSettingsOperation::StoreSettingsOperation(
    const Callback& callback,
    scoped_ptr<em::PolicyFetchResponse> policy)
    : SessionManagerOperation(callback),
      policy_(policy.Pass()),
      weak_factory_(this) {}

StoreSettingsOperation::~StoreSettingsOperation() {}

void StoreSettingsOperation::Run() {
  session_manager_client()->StoreDevicePolicy(
      policy_->SerializeAsString(),
      base::Bind(&StoreSettingsOperation::HandleStoreResult,
                 weak_factory_.GetWeakPtr()));
}

void StoreSettingsOperation::HandleStoreResult(bool success) {
  if (!success)
    ReportResult(DeviceSettingsService::STORE_OPERATION_FAILED);
  else
    StartLoading();
}

SignAndStoreSettingsOperation::SignAndStoreSettingsOperation(
    const Callback& callback,
    scoped_ptr<em::ChromeDeviceSettingsProto> new_settings,
    const std::string& username)
    : SessionManagerOperation(callback),
      new_settings_(new_settings.Pass()),
      username_(username),
      weak_factory_(this) {
  DCHECK(new_settings_.get());
}

SignAndStoreSettingsOperation::~SignAndStoreSettingsOperation() {}

void SignAndStoreSettingsOperation::Run() {
  EnsureOwnerKey(base::Bind(&SignAndStoreSettingsOperation::StartSigning,
                            weak_factory_.GetWeakPtr()));
}

void SignAndStoreSettingsOperation::StartSigning() {
  if (!owner_key().get() || !owner_key()->private_key() || username_.empty()) {
    ReportResult(DeviceSettingsService::STORE_KEY_UNAVAILABLE);
    return;
  }

  base::PostTaskAndReplyWithResult(
      content::BrowserThread::GetBlockingPool(),
      FROM_HERE,
      base::Bind(&SignAndStoreSettingsOperation::AssembleAndSignPolicy,
                 base::Passed(&new_settings_), username_, owner_key()),
      base::Bind(&SignAndStoreSettingsOperation::StoreDeviceSettingsBlob,
                 weak_factory_.GetWeakPtr()));
}

// static
std::string SignAndStoreSettingsOperation::AssembleAndSignPolicy(
    scoped_ptr<em::ChromeDeviceSettingsProto> device_settings,
    const std::string& username,
    scoped_refptr<OwnerKey> owner_key) {
  // Assemble the policy.
  em::PolicyFetchResponse policy_response;
  em::PolicyData policy;
  policy.set_policy_type(policy::dm_protocol::kChromeDevicePolicyType);
  policy.set_timestamp((base::Time::NowFromSystemTime() -
                        base::Time::UnixEpoch()).InMilliseconds());
  policy.set_username(username);
  if (!device_settings->SerializeToString(policy.mutable_policy_value()) ||
      !policy.SerializeToString(policy_response.mutable_policy_data())) {
    LOG(ERROR) << "Failed to encode policy payload.";
    return std::string();
  }

  // Generate the signature.
  scoped_ptr<crypto::SignatureCreator> signature_creator(
      crypto::SignatureCreator::Create(owner_key->private_key()));
  signature_creator->Update(
      reinterpret_cast<const uint8*>(policy_response.policy_data().c_str()),
      policy_response.policy_data().size());
  std::vector<uint8> signature_bytes;
  std::string policy_blob;
  if (!signature_creator->Final(&signature_bytes)) {
    LOG(ERROR) << "Failed to create policy signature.";
    return std::string();
  }

  policy_response.mutable_policy_data_signature()->assign(
      reinterpret_cast<const char*>(vector_as_array(&signature_bytes)),
      signature_bytes.size());
  return policy_response.SerializeAsString();
}

void SignAndStoreSettingsOperation::StoreDeviceSettingsBlob(
    std::string device_settings_blob) {
  if (device_settings_blob.empty()) {
    ReportResult(DeviceSettingsService::STORE_POLICY_ERROR);
    return;
  }

  session_manager_client()->StoreDevicePolicy(
      device_settings_blob,
      base::Bind(&SignAndStoreSettingsOperation::HandleStoreResult,
                 weak_factory_.GetWeakPtr()));
}

void SignAndStoreSettingsOperation::HandleStoreResult(bool success) {
  if (!success)
    ReportResult(DeviceSettingsService::STORE_OPERATION_FAILED);
  else
    StartLoading();
}

}  // namespace chromeos

/* [<][>][^][v][top][bottom][index][help] */