chromium/chrome/browser/ash/policy/arc/android_management_client.cc

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/policy/arc/android_management_client.h"

#include <utility>

#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/uuid.h"
#include "components/policy/core/common/cloud/device_management_service.h"
#include "components/policy/core/common/cloud/dm_auth.h"
#include "components/policy/core/common/cloud/dmserver_job_configurations.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "components/signin/public/identity_manager/access_token_fetcher.h"
#include "components/signin/public/identity_manager/access_token_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/scope_set.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"

namespace em = enterprise_management;

namespace policy {

AndroidManagementClientImpl::AndroidManagementClientImpl(
    DeviceManagementService* device_management_service,
    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
    const CoreAccountId& account_id,
    signin::IdentityManager* identity_manager)
    : device_management_service_(device_management_service),
      url_loader_factory_(url_loader_factory),
      account_id_(account_id),
      identity_manager_(identity_manager) {
  device_management_service_->ScheduleInitialization(0);
}

AndroidManagementClientImpl::~AndroidManagementClientImpl() = default;

void AndroidManagementClientImpl::StartCheckAndroidManagement(
    StatusCallback callback) {
  DCHECK(device_management_service_);
  DCHECK(callback_.is_null());

  callback_ = std::move(callback);
  RequestAccessToken();
}

void AndroidManagementClientImpl::OnAccessTokenFetchComplete(
    GoogleServiceAuthError error,
    signin::AccessTokenInfo token_info) {
  access_token_fetcher_.reset();

  if (error.state() != GoogleServiceAuthError::NONE) {
    LOG(ERROR) << "Token request failed: " << error.ToString();
    DCHECK(!callback_.is_null());
    std::move(callback_).Run(Result::ERROR);
    return;
  }

  CheckAndroidManagement(token_info.token);
}

void AndroidManagementClientImpl::RequestAccessToken() {
  DCHECK(!access_token_fetcher_);
  // The user must be signed in already.
  DCHECK(identity_manager_->HasAccountWithRefreshToken(account_id_));

  signin::ScopeSet scopes;
  scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
  scopes.insert(GaiaConstants::kGoogleUserInfoEmail);

  access_token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForAccount(
      account_id_, "android_management_client", scopes,
      base::BindOnce(&AndroidManagementClientImpl::OnAccessTokenFetchComplete,
                     base::Unretained(this)),
      signin::AccessTokenFetcher::Mode::kImmediate);
}

void AndroidManagementClientImpl::CheckAndroidManagement(
    const std::string& access_token) {
  std::unique_ptr<DMServerJobConfiguration> config = std::make_unique<
      DMServerJobConfiguration>(
      device_management_service_,
      DeviceManagementService::JobConfiguration::TYPE_ANDROID_MANAGEMENT_CHECK,
      /*client_id=*/base::Uuid::GenerateRandomV4().AsLowercaseString(),
      /*critical=*/false, DMAuth::NoAuth(), access_token, url_loader_factory_,
      base::BindOnce(&AndroidManagementClientImpl::OnAndroidManagementChecked,
                     weak_ptr_factory_.GetWeakPtr()));

  config->request()->mutable_check_android_management_request();

  request_job_ = device_management_service_->CreateJob(std::move(config));
}

void AndroidManagementClientImpl::OnAndroidManagementChecked(
    DMServerJobResult result) {
  DCHECK(!callback_.is_null());
  if (result.dm_status == DM_STATUS_SUCCESS &&
      !result.response.has_check_android_management_response()) {
    LOG(WARNING) << "Invalid check android management response.";
    result.dm_status = DM_STATUS_RESPONSE_DECODING_ERROR;
  }

  Result management_result;
  switch (result.dm_status) {
    case DM_STATUS_SUCCESS:
      management_result = Result::UNMANAGED;
      break;
    case DM_STATUS_SERVICE_DEVICE_ID_CONFLICT:
      management_result = Result::MANAGED;
      break;
    default:
      management_result = Result::ERROR;
  }

  request_job_.reset();
  std::move(callback_).Run(management_result);
}

std::ostream& operator<<(std::ostream& os,
                         AndroidManagementClient::Result result) {
  switch (result) {
    case AndroidManagementClient::Result::MANAGED:
      return os << "MANAGED";
    case AndroidManagementClient::Result::UNMANAGED:
      return os << "UNMANAGED";
    case AndroidManagementClient::Result::ERROR:
      return os << "ERROR";
  }
  NOTREACHED_IN_MIGRATION();
  return os;
}

}  // namespace policy