This source file includes following definitions.
- weak_ptr_factory_
 
- StartEnrollment
 
- ReleaseClient
 
- OnPolicyFetched
 
- OnRegistrationStateChanged
 
- OnClientError
 
- OnStoreLoaded
 
- OnStoreError
 
- AttemptRegistration
 
- PolicyValidated
 
- OnRobotAuthCodesFetched
 
- OnGetTokensResponse
 
- OnRefreshTokenResponse
 
- OnOAuthError
 
- OnNetworkError
 
- StartLockDevice
 
- HandleLockDeviceResult
 
- HandleRobotAuthTokenStored
 
- Stop
 
- ReportResult
 
#include "chrome/browser/chromeos/policy/enrollment_handler_chromeos.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
#include "chromeos/chromeos_switches.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/http/http_status_code.h"
#include "policy/proto/device_management_backend.pb.h"
namespace em = enterprise_management;
namespace policy {
namespace {
const int kLockRetryIntervalMs = 500;
const int kLockRetryTimeoutMs = 10 * 60 * 1000;  
const char kTestingRobotToken[] = "test-token";
}  
EnrollmentHandlerChromeOS::EnrollmentHandlerChromeOS(
    DeviceCloudPolicyStoreChromeOS* store,
    EnterpriseInstallAttributes* install_attributes,
    scoped_ptr<CloudPolicyClient> client,
    scoped_refptr<base::SequencedTaskRunner> background_task_runner,
    const std::string& auth_token,
    const std::string& client_id,
    bool is_auto_enrollment,
    const std::string& requisition,
    const std::string& current_state_key,
    const AllowedDeviceModes& allowed_device_modes,
    const EnrollmentCallback& completion_callback)
    : store_(store),
      install_attributes_(install_attributes),
      client_(client.Pass()),
      background_task_runner_(background_task_runner),
      auth_token_(auth_token),
      client_id_(client_id),
      is_auto_enrollment_(is_auto_enrollment),
      requisition_(requisition),
      current_state_key_(current_state_key),
      allowed_device_modes_(allowed_device_modes),
      completion_callback_(completion_callback),
      device_mode_(DEVICE_MODE_NOT_SET),
      enrollment_step_(STEP_PENDING),
      lockbox_init_duration_(0),
      weak_ptr_factory_(this) {
  CHECK(!client_->is_registered());
  CHECK_EQ(DM_STATUS_SUCCESS, client_->status());
  store_->AddObserver(this);
  client_->AddObserver(this);
  client_->AddNamespaceToFetch(PolicyNamespaceKey(
      dm_protocol::kChromeDevicePolicyType, std::string()));
}
EnrollmentHandlerChromeOS::~EnrollmentHandlerChromeOS() {
  Stop();
  store_->RemoveObserver(this);
}
void EnrollmentHandlerChromeOS::StartEnrollment() {
  CHECK_EQ(STEP_PENDING, enrollment_step_);
  enrollment_step_ = STEP_LOADING_STORE;
  AttemptRegistration();
}
scoped_ptr<CloudPolicyClient> EnrollmentHandlerChromeOS::ReleaseClient() {
  Stop();
  return client_.Pass();
}
void EnrollmentHandlerChromeOS::OnPolicyFetched(CloudPolicyClient* client) {
  DCHECK_EQ(client_.get(), client);
  CHECK_EQ(STEP_POLICY_FETCH, enrollment_step_);
  enrollment_step_ = STEP_VALIDATION;
  
  const em::PolicyFetchResponse* policy = client_->GetPolicyFor(
      PolicyNamespaceKey(dm_protocol::kChromeDevicePolicyType, std::string()));
  if (!policy) {
    ReportResult(EnrollmentStatus::ForFetchError(
        DM_STATUS_RESPONSE_DECODING_ERROR));
    return;
  }
  scoped_ptr<DeviceCloudPolicyValidator> validator(
      DeviceCloudPolicyValidator::Create(
          scoped_ptr<em::PolicyFetchResponse>(
              new em::PolicyFetchResponse(*policy)),
          background_task_runner_));
  validator->ValidateTimestamp(base::Time(), base::Time::NowFromSystemTime(),
                               CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
  
  
  std::string domain;
  if (install_attributes_->IsEnterpriseDevice()) {
    domain = install_attributes_->GetDomain();
    validator->ValidateDomain(domain);
  }
  validator->ValidateDMToken(client->dm_token(),
                             CloudPolicyValidatorBase::DM_TOKEN_REQUIRED);
  validator->ValidatePolicyType(dm_protocol::kChromeDevicePolicyType);
  validator->ValidatePayload();
  
  
  
  
  
  validator->ValidateInitialKey(GetPolicyVerificationKey(), domain);
  validator.release()->StartValidation(
      base::Bind(&EnrollmentHandlerChromeOS::PolicyValidated,
                 weak_ptr_factory_.GetWeakPtr()));
}
void EnrollmentHandlerChromeOS::OnRegistrationStateChanged(
    CloudPolicyClient* client) {
  DCHECK_EQ(client_.get(), client);
  if (enrollment_step_ == STEP_REGISTRATION && client_->is_registered()) {
    enrollment_step_ = STEP_POLICY_FETCH,
    device_mode_ = client_->device_mode();
    if (device_mode_ == DEVICE_MODE_NOT_SET)
      device_mode_ = DEVICE_MODE_ENTERPRISE;
    if (!allowed_device_modes_.test(device_mode_)) {
      LOG(ERROR) << "Bad device mode " << device_mode_;
      ReportResult(EnrollmentStatus::ForStatus(
          EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE));
      return;
    }
    client_->FetchPolicy();
  } else {
    LOG(FATAL) << "Registration state changed to " << client_->is_registered()
               << " in step " << enrollment_step_;
  }
}
void EnrollmentHandlerChromeOS::OnClientError(CloudPolicyClient* client) {
  DCHECK_EQ(client_.get(), client);
  if (enrollment_step_ == STEP_ROBOT_AUTH_FETCH) {
    LOG(ERROR) << "API authentication code fetch failed: "
               << client_->status();
    ReportResult(EnrollmentStatus::ForRobotAuthFetchError(client_->status()));
  } else if (enrollment_step_ < STEP_POLICY_FETCH) {
    ReportResult(EnrollmentStatus::ForRegistrationError(client_->status()));
  } else {
    ReportResult(EnrollmentStatus::ForFetchError(client_->status()));
  }
}
void EnrollmentHandlerChromeOS::OnStoreLoaded(CloudPolicyStore* store) {
  DCHECK_EQ(store_, store);
  if (enrollment_step_ == STEP_LOADING_STORE) {
    
    
    
    AttemptRegistration();
  } else if (enrollment_step_ == STEP_STORE_POLICY) {
    ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS));
  }
}
void EnrollmentHandlerChromeOS::OnStoreError(CloudPolicyStore* store) {
  DCHECK_EQ(store_, store);
  ReportResult(EnrollmentStatus::ForStoreError(store_->status(),
                                               store_->validation_status()));
}
void EnrollmentHandlerChromeOS::AttemptRegistration() {
  CHECK_EQ(STEP_LOADING_STORE, enrollment_step_);
  if (store_->is_initialized()) {
    enrollment_step_ = STEP_REGISTRATION;
    client_->Register(em::DeviceRegisterRequest::DEVICE,
                      auth_token_, client_id_, is_auto_enrollment_,
                      requisition_, current_state_key_);
  }
}
void EnrollmentHandlerChromeOS::PolicyValidated(
    DeviceCloudPolicyValidator* validator) {
  CHECK_EQ(STEP_VALIDATION, enrollment_step_);
  if (validator->success()) {
    policy_ = validator->policy().Pass();
    username_ = validator->policy_data()->username();
    device_id_ = validator->policy_data()->device_id();
    if (CommandLine::ForCurrentProcess()->HasSwitch(
            chromeos::switches::kEnterpriseEnrollmentSkipRobotAuth)) {
      
      
      refresh_token_ = kTestingRobotToken;
      enrollment_step_ = STEP_LOCK_DEVICE,
      StartLockDevice(username_, device_mode_, device_id_);
      return;
    }
    enrollment_step_ = STEP_ROBOT_AUTH_FETCH;
    client_->FetchRobotAuthCodes(auth_token_);
  } else {
    ReportResult(EnrollmentStatus::ForValidationError(validator->status()));
  }
}
void EnrollmentHandlerChromeOS::OnRobotAuthCodesFetched(
    CloudPolicyClient* client) {
  DCHECK_EQ(client_.get(), client);
  CHECK_EQ(STEP_ROBOT_AUTH_FETCH, enrollment_step_);
  enrollment_step_ = STEP_ROBOT_AUTH_REFRESH;
  gaia::OAuthClientInfo client_info;
  client_info.client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
  client_info.client_secret =
      GaiaUrls::GetInstance()->oauth2_chrome_client_secret();
  client_info.redirect_uri = "oob";
  
  gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
      g_browser_process->system_request_context()));
  gaia_oauth_client_->GetTokensFromAuthCode(client_info,
                                            client->robot_api_auth_code(),
                                            0 ,
                                            this);
}
void EnrollmentHandlerChromeOS::OnGetTokensResponse(
    const std::string& refresh_token,
    const std::string& access_token,
    int expires_in_seconds) {
  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
  refresh_token_ = refresh_token;
  enrollment_step_ = STEP_LOCK_DEVICE,
  StartLockDevice(username_, device_mode_, device_id_);
}
void EnrollmentHandlerChromeOS::OnRefreshTokenResponse(
    const std::string& access_token,
    int expires_in_seconds) {
  
  LOG(FATAL) << "Unexpected callback invoked";
}
void EnrollmentHandlerChromeOS::OnOAuthError() {
  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
  
  
  LOG(ERROR) << "OAuth protocol error while fetching API refresh token.";
  ReportResult(
      EnrollmentStatus::ForRobotRefreshFetchError(net::HTTP_BAD_REQUEST));
}
void EnrollmentHandlerChromeOS::OnNetworkError(int response_code) {
  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
  LOG(ERROR) << "Network error while fetching API refresh token: "
             << response_code;
  ReportResult(
      EnrollmentStatus::ForRobotRefreshFetchError(response_code));
}
void EnrollmentHandlerChromeOS::StartLockDevice(
    const std::string& user,
    DeviceMode device_mode,
    const std::string& device_id) {
  CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
  
  weak_ptr_factory_.InvalidateWeakPtrs();
  install_attributes_->LockDevice(
      user, device_mode, device_id,
      base::Bind(&EnrollmentHandlerChromeOS::HandleLockDeviceResult,
                 weak_ptr_factory_.GetWeakPtr(),
                 user,
                 device_mode,
                 device_id));
}
void EnrollmentHandlerChromeOS::HandleLockDeviceResult(
    const std::string& user,
    DeviceMode device_mode,
    const std::string& device_id,
    EnterpriseInstallAttributes::LockResult lock_result) {
  CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
  switch (lock_result) {
    case EnterpriseInstallAttributes::LOCK_SUCCESS:
      
      enrollment_step_ = STEP_STORE_ROBOT_AUTH;
      chromeos::DeviceOAuth2TokenServiceFactory::Get()->SetAndSaveRefreshToken(
          refresh_token_,
          base::Bind(&EnrollmentHandlerChromeOS::HandleRobotAuthTokenStored,
                     weak_ptr_factory_.GetWeakPtr()));
      return;
    case EnterpriseInstallAttributes::LOCK_NOT_READY:
      
      
      if (lockbox_init_duration_ < kLockRetryTimeoutMs) {
        
        LOG(WARNING) << "Install Attributes not ready yet will retry in "
                     << kLockRetryIntervalMs << "ms.";
        base::MessageLoop::current()->PostDelayedTask(
            FROM_HERE,
            base::Bind(&EnrollmentHandlerChromeOS::StartLockDevice,
                       weak_ptr_factory_.GetWeakPtr(),
                       user, device_mode, device_id),
            base::TimeDelta::FromMilliseconds(kLockRetryIntervalMs));
        lockbox_init_duration_ += kLockRetryIntervalMs;
      } else {
        ReportResult(EnrollmentStatus::ForStatus(
            EnrollmentStatus::STATUS_LOCK_TIMEOUT));
      }
      return;
    case EnterpriseInstallAttributes::LOCK_BACKEND_ERROR:
      ReportResult(EnrollmentStatus::ForStatus(
          EnrollmentStatus::STATUS_LOCK_ERROR));
      return;
    case EnterpriseInstallAttributes::LOCK_WRONG_USER:
      LOG(ERROR) << "Enrollment cannot proceed because the InstallAttrs "
                 << "has been locked already!";
      ReportResult(EnrollmentStatus::ForStatus(
          EnrollmentStatus::STATUS_LOCK_WRONG_USER));
      return;
  }
  NOTREACHED() << "Invalid lock result " << lock_result;
  ReportResult(EnrollmentStatus::ForStatus(
      EnrollmentStatus::STATUS_LOCK_ERROR));
}
void EnrollmentHandlerChromeOS::HandleRobotAuthTokenStored(bool result) {
  CHECK_EQ(STEP_STORE_ROBOT_AUTH, enrollment_step_);
  if (!result) {
    LOG(ERROR) << "Failed to store API refresh token.";
    ReportResult(EnrollmentStatus::ForStatus(
        EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED));
    return;
  }
  enrollment_step_ = STEP_STORE_POLICY;
  store_->InstallInitialPolicy(*policy_);
}
void EnrollmentHandlerChromeOS::Stop() {
  if (client_.get())
    client_->RemoveObserver(this);
  enrollment_step_ = STEP_FINISHED;
  weak_ptr_factory_.InvalidateWeakPtrs();
  completion_callback_.Reset();
}
void EnrollmentHandlerChromeOS::ReportResult(EnrollmentStatus status) {
  EnrollmentCallback callback = completion_callback_;
  Stop();
  if (status.status() != EnrollmentStatus::STATUS_SUCCESS) {
    LOG(WARNING) << "Enrollment failed: " << status.status()
                 << " " << status.client_status()
                 << " " << status.validation_status()
                 << " " << status.store_status();
  }
  if (!callback.is_null())
    callback.Run(status);
}
}