blob: be4700ebb0bef87933a62461a1c65de72416173a [file] [log] [blame]
// 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 "components/policy/core/common/cloud/cloud_policy_client.h"
#include "build/build_config.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "components/policy/core/common/cloud/cloud_policy_util.h"
#include "components/policy/core/common/cloud/device_management_service.h"
#include "components/policy/core/common/cloud/signing_service.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/url_request/url_request_context_getter.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace em = enterprise_management;
namespace policy {
namespace {
// Translates the DeviceRegisterResponse::DeviceMode |mode| to the enum used
// internally to represent different device modes.
DeviceMode TranslateProtobufDeviceMode(
em::DeviceRegisterResponse::DeviceMode mode) {
switch (mode) {
case em::DeviceRegisterResponse::ENTERPRISE:
return DEVICE_MODE_ENTERPRISE;
case em::DeviceRegisterResponse::RETAIL:
return DEVICE_MODE_LEGACY_RETAIL_MODE;
case em::DeviceRegisterResponse::CHROME_AD:
return DEVICE_MODE_ENTERPRISE_AD;
}
LOG(ERROR) << "Unknown enrollment mode in registration response: " << mode;
return DEVICE_MODE_NOT_SET;
}
bool IsChromePolicy(const std::string& type) {
return type == dm_protocol::kChromeDevicePolicyType ||
type == dm_protocol::kChromeUserPolicyType ||
type == dm_protocol::kChromeMachineLevelUserCloudPolicyType;
}
LicenseType TranslateLicenseType(em::LicenseType type) {
switch (type.license_type()) {
case em::LicenseType::UNDEFINED:
LOG(ERROR) << "Unknown License type: " << type.license_type();
return LicenseType::UNKNOWN;
case em::LicenseType::CDM_PERPETUAL:
return LicenseType::PERPETUAL;
case em::LicenseType::CDM_ANNUAL:
return LicenseType::ANNUAL;
case em::LicenseType::KIOSK:
return LicenseType::KIOSK;
}
NOTREACHED();
return LicenseType::UNKNOWN;
}
void ExtractLicenseMap(const em::CheckDeviceLicenseResponse& license_response,
CloudPolicyClient::LicenseMap& licenses) {
for (int i = 0; i < license_response.license_availability_size(); i++) {
const em::LicenseAvailability& license =
license_response.license_availability(i);
if (!license.has_license_type() || !license.has_available_licenses())
continue;
auto license_type = TranslateLicenseType(license.license_type());
if (license_type == LicenseType::UNKNOWN)
continue;
bool duplicate =
licenses
.insert(std::make_pair(license_type, license.available_licenses()))
.second;
if (duplicate) {
LOG(WARNING) << "Duplicate license type in response :"
<< static_cast<int>(license_type);
}
}
}
} // namespace
CloudPolicyClient::Observer::~Observer() {}
void CloudPolicyClient::Observer::OnRobotAuthCodesFetched(
CloudPolicyClient* client) {}
CloudPolicyClient::CloudPolicyClient(
const std::string& machine_id,
const std::string& machine_model,
const std::string& brand_code,
DeviceManagementService* service,
scoped_refptr<net::URLRequestContextGetter> request_context,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
SigningService* signing_service,
DeviceDMTokenCallback device_dm_token_callback)
: machine_id_(machine_id),
machine_model_(machine_model),
brand_code_(brand_code),
service_(service), // Can be null for unit tests.
signing_service_(signing_service),
device_dm_token_callback_(device_dm_token_callback),
request_context_(request_context),
url_loader_factory_(url_loader_factory),
weak_ptr_factory_(this) {}
CloudPolicyClient::~CloudPolicyClient() {
}
void CloudPolicyClient::SetupRegistration(
const std::string& dm_token,
const std::string& client_id,
const std::vector<std::string>& user_affiliation_ids) {
DCHECK(!dm_token.empty());
DCHECK(!client_id.empty());
DCHECK(!is_registered());
dm_token_ = dm_token;
client_id_ = client_id;
request_jobs_.clear();
app_install_report_request_job_ = nullptr;
policy_fetch_request_job_.reset();
responses_.clear();
if (device_dm_token_callback_) {
device_dm_token_ = device_dm_token_callback_.Run(user_affiliation_ids);
}
NotifyRegistrationStateChanged();
}
// Sets the client ID or generate a new one. A new one is intentionally
// generated on each new registration request in order to preserve privacy.
// Reusing IDs would mean the server could track clients by their registration
// attempts.
void CloudPolicyClient::SetClientId(const std::string& client_id) {
client_id_ = client_id.empty() ? base::GenerateGUID() : client_id;
}
void CloudPolicyClient::Register(em::DeviceRegisterRequest::Type type,
em::DeviceRegisterRequest::Flavor flavor,
em::DeviceRegisterRequest::Lifetime lifetime,
em::LicenseType::LicenseTypeEnum license_type,
const std::string& auth_token,
const std::string& client_id,
const std::string& requisition,
const std::string& current_state_key) {
DCHECK(service_);
DCHECK(!auth_token.empty());
DCHECK(!is_registered());
SetClientId(client_id);
policy_fetch_request_job_.reset(
service_->CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION,
GetRequestContext()));
policy_fetch_request_job_->SetOAuthToken(auth_token);
policy_fetch_request_job_->SetClientID(client_id_);
em::DeviceRegisterRequest* request =
policy_fetch_request_job_->GetRequest()->mutable_register_request();
if (!client_id.empty())
request->set_reregister(true);
request->set_type(type);
if (!machine_id_.empty())
request->set_machine_id(machine_id_);
if (!machine_model_.empty())
request->set_machine_model(machine_model_);
if (!brand_code_.empty())
request->set_brand_code(brand_code_);
if (!requisition.empty())
request->set_requisition(requisition);
if (!current_state_key.empty())
request->set_server_backed_state_key(current_state_key);
request->set_flavor(flavor);
if (license_type != em::LicenseType::UNDEFINED)
request->mutable_license_type()->set_license_type(license_type);
request->set_lifetime(lifetime);
policy_fetch_request_job_->SetRetryCallback(
base::Bind(&CloudPolicyClient::OnRetryRegister,
weak_ptr_factory_.GetWeakPtr()));
policy_fetch_request_job_->Start(
base::Bind(&CloudPolicyClient::OnRegisterCompleted,
weak_ptr_factory_.GetWeakPtr()));
}
void CloudPolicyClient::RegisterWithCertificate(
em::DeviceRegisterRequest::Type type,
em::DeviceRegisterRequest::Flavor flavor,
em::DeviceRegisterRequest::Lifetime lifetime,
em::LicenseType::LicenseTypeEnum license_type,
const std::string& pem_certificate_chain,
const std::string& client_id,
const std::string& requisition,
const std::string& current_state_key) {
DCHECK(signing_service_);
DCHECK(service_);
DCHECK(!is_registered());
SetClientId(client_id);
em::CertificateBasedDeviceRegistrationData data;
data.set_certificate_type(em::CertificateBasedDeviceRegistrationData::
ENTERPRISE_ENROLLMENT_CERTIFICATE);
data.set_device_certificate(pem_certificate_chain);
em::DeviceRegisterRequest* request = data.mutable_device_register_request();
if (!client_id.empty())
request->set_reregister(true);
request->set_type(type);
if (!machine_id_.empty())
request->set_machine_id(machine_id_);
if (!machine_model_.empty())
request->set_machine_model(machine_model_);
if (!brand_code_.empty())
request->set_brand_code(brand_code_);
if (!requisition.empty())
request->set_requisition(requisition);
if (!current_state_key.empty())
request->set_server_backed_state_key(current_state_key);
request->set_flavor(flavor);
if (license_type != em::LicenseType::UNDEFINED)
request->mutable_license_type()->set_license_type(license_type);
request->set_lifetime(lifetime);
signing_service_->SignData(data.SerializeAsString(),
base::Bind(&CloudPolicyClient::OnRegisterWithCertificateRequestSigned,
weak_ptr_factory_.GetWeakPtr()));
}
void CloudPolicyClient::RegisterWithToken(const std::string& token,
const std::string& client_id) {
DCHECK(service_);
DCHECK(!token.empty());
DCHECK(!client_id.empty());
DCHECK(!is_registered());
SetClientId(client_id);
policy_fetch_request_job_.reset(service_->CreateJob(
DeviceManagementRequestJob::TYPE_TOKEN_ENROLLMENT, GetRequestContext()));
policy_fetch_request_job_->SetEnrollmentToken(token);
policy_fetch_request_job_->SetClientID(client_id_);
enterprise_management::RegisterBrowserRequest* request =
policy_fetch_request_job_->GetRequest()
->mutable_register_browser_request();
request->set_machine_name(GetMachineName());
request->set_os_platform(GetOSPlatform());
request->set_os_version(GetOSVersion());
policy_fetch_request_job_->SetRetryCallback(base::Bind(
&CloudPolicyClient::OnRetryRegister, weak_ptr_factory_.GetWeakPtr()));
policy_fetch_request_job_->Start(
base::Bind(&CloudPolicyClient::OnRegisterCompleted,
weak_ptr_factory_.GetWeakPtr()));
}
void CloudPolicyClient::OnRegisterWithCertificateRequestSigned(bool success,
em::SignedData signed_data) {
if (!success) {
const em::DeviceManagementResponse response;
OnRegisterCompleted(DM_STATUS_CANNOT_SIGN_REQUEST, 0, response);
return;
}
policy_fetch_request_job_.reset(
service_->CreateJob(
DeviceManagementRequestJob::TYPE_CERT_BASED_REGISTRATION,
GetRequestContext()));
policy_fetch_request_job_->SetClientID(client_id_);
em::SignedData* signed_request = policy_fetch_request_job_->GetRequest()->
mutable_certificate_based_register_request()->mutable_signed_request();
signed_request->set_data(signed_data.data());
signed_request->set_signature(signed_data.signature());
signed_request->set_extra_data_bytes(signed_data.extra_data_bytes());
policy_fetch_request_job_->SetRetryCallback(
base::Bind(&CloudPolicyClient::OnRetryRegister,
weak_ptr_factory_.GetWeakPtr()));
policy_fetch_request_job_->Start(
base::Bind(&CloudPolicyClient::OnRegisterCompleted,
weak_ptr_factory_.GetWeakPtr()));
}
void CloudPolicyClient::SetInvalidationInfo(int64_t version,
const std::string& payload) {
invalidation_version_ = version;
invalidation_payload_ = payload;
}
void CloudPolicyClient::FetchPolicy() {
CHECK(is_registered());
CHECK(!types_to_fetch_.empty());
policy_fetch_request_job_.reset(
service_->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH,
GetRequestContext()));
policy_fetch_request_job_->SetDMToken(dm_token_);
policy_fetch_request_job_->SetClientID(client_id_);
if (!public_key_version_valid_)
policy_fetch_request_job_->SetCritical(true);
em::DeviceManagementRequest* request =
policy_fetch_request_job_->GetRequest();
// Build policy fetch requests.
em::DevicePolicyRequest* policy_request = request->mutable_policy_request();
for (const auto& type_to_fetch : types_to_fetch_) {
em::PolicyFetchRequest* fetch_request = policy_request->add_request();
fetch_request->set_policy_type(type_to_fetch.first);
if (!type_to_fetch.second.empty())
fetch_request->set_settings_entity_id(type_to_fetch.second);
// Request signed policy blobs to help prevent tampering on the client.
fetch_request->set_signature_type(em::PolicyFetchRequest::SHA1_RSA);
if (public_key_version_valid_)
fetch_request->set_public_key_version(public_key_version_);
fetch_request->set_verification_key_hash(kPolicyVerificationKeyHash);
// These fields are included only in requests for chrome policy.
if (IsChromePolicy(type_to_fetch.first)) {
if (!device_dm_token_.empty())
fetch_request->set_device_dm_token(device_dm_token_);
if (!last_policy_timestamp_.is_null())
fetch_request->set_timestamp(last_policy_timestamp_.ToJavaTime());
if (!invalidation_payload_.empty()) {
fetch_request->set_invalidation_version(invalidation_version_);
fetch_request->set_invalidation_payload(invalidation_payload_);
}
}
}
// Add device state keys.
if (!state_keys_to_upload_.empty()) {
em::DeviceStateKeyUpdateRequest* key_update_request =
request->mutable_device_state_key_update_request();
for (std::vector<std::string>::const_iterator key(
state_keys_to_upload_.begin());
key != state_keys_to_upload_.end();
++key) {
key_update_request->add_server_backed_state_key(*key);
}
}
// Set the fetched invalidation version to the latest invalidation version
// since it is now the invalidation version used for the latest fetch.
fetched_invalidation_version_ = invalidation_version_;
// Fire the job.
policy_fetch_request_job_->Start(
base::Bind(&CloudPolicyClient::OnPolicyFetchCompleted,
weak_ptr_factory_.GetWeakPtr()));
}
void CloudPolicyClient::FetchRobotAuthCodes(const std::string& auth_token) {
CHECK(is_registered());
policy_fetch_request_job_.reset(service_->CreateJob(
DeviceManagementRequestJob::TYPE_API_AUTH_CODE_FETCH,
GetRequestContext()));
policy_fetch_request_job_->SetOAuthToken(auth_token);
policy_fetch_request_job_->SetDMToken(dm_token_);
policy_fetch_request_job_->SetClientID(client_id_);
em::DeviceServiceApiAccessRequest* request =
policy_fetch_request_job_->GetRequest()->
mutable_service_api_access_request();
request->set_oauth2_client_id(
GaiaUrls::GetInstance()->oauth2_chrome_client_id());
request->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope);
request->set_device_type(em::DeviceServiceApiAccessRequest::CHROME_OS);
policy_fetch_request_job_->Start(
base::Bind(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
weak_ptr_factory_.GetWeakPtr()));
}
void CloudPolicyClient::Unregister() {
DCHECK(service_);
policy_fetch_request_job_.reset(
service_->CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION,
GetRequestContext()));
policy_fetch_request_job_->SetDMToken(dm_token_);
policy_fetch_request_job_->SetClientID(client_id_);
policy_fetch_request_job_->GetRequest()->mutable_unregister_request();
policy_fetch_request_job_->Start(
base::Bind(&CloudPolicyClient::OnUnregisterCompleted,
weak_ptr_factory_.GetWeakPtr()));
}
void CloudPolicyClient::UploadEnterpriseMachineCertificate(
const std::string& certificate_data,
const CloudPolicyClient::StatusCallback& callback) {
UploadCertificate(certificate_data,
em::DeviceCertUploadRequest::ENTERPRISE_MACHINE_CERTIFICATE,
callback);
}
void CloudPolicyClient::UploadEnterpriseEnrollmentCertificate(
const std::string& certificate_data,
const CloudPolicyClient::StatusCallback& callback) {
UploadCertificate(
certificate_data,
em::DeviceCertUploadRequest::ENTERPRISE_ENROLLMENT_CERTIFICATE, callback);
}
void CloudPolicyClient::UploadEnterpriseEnrollmentId(
const std::string& enrollment_id,
const CloudPolicyClient::StatusCallback& callback) {
CHECK(is_registered());
std::unique_ptr<DeviceManagementRequestJob> request_job(
service_->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_CERTIFICATE,
GetRequestContext()));
request_job->SetDMToken(dm_token_);
request_job->SetClientID(client_id_);
em::DeviceManagementRequest* request = request_job->GetRequest();
em::DeviceCertUploadRequest* upload_request =
request->mutable_cert_upload_request();
upload_request->set_enrollment_id(enrollment_id);
const DeviceManagementRequestJob::Callback job_callback = base::BindRepeating(
&CloudPolicyClient::OnCertificateUploadCompleted,
weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback);
request_jobs_.push_back(std::move(request_job));
request_jobs_.back()->Start(job_callback);
}
void CloudPolicyClient::UploadDeviceStatus(
const em::DeviceStatusReportRequest* device_status,
const em::SessionStatusReportRequest* session_status,
const CloudPolicyClient::StatusCallback& callback) {
CHECK(is_registered());
// Should pass in at least one type of status.
DCHECK(device_status || session_status);
std::unique_ptr<DeviceManagementRequestJob> request_job(service_->CreateJob(
DeviceManagementRequestJob::TYPE_UPLOAD_STATUS, GetRequestContext()));
request_job->SetDMToken(dm_token_);
request_job->SetClientID(client_id_);
em::DeviceManagementRequest* request = request_job->GetRequest();
if (device_status)
*request->mutable_device_status_report_request() = *device_status;
if (session_status)
*request->mutable_session_status_report_request() = *session_status;
const DeviceManagementRequestJob::Callback job_callback =
base::AdaptCallbackForRepeating(base::BindOnce(
&CloudPolicyClient::OnReportUploadCompleted,
weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback));
request_jobs_.push_back(std::move(request_job));
request_jobs_.back()->Start(job_callback);
}
void CloudPolicyClient::UploadChromeDesktopReport(
std::unique_ptr<em::ChromeDesktopReportRequest> chrome_desktop_report,
const CloudPolicyClient::StatusCallback& callback) {
CHECK(is_registered());
DCHECK(chrome_desktop_report);
std::unique_ptr<DeviceManagementRequestJob> request_job(service_->CreateJob(
DeviceManagementRequestJob::TYPE_CHROME_DESKTOP_REPORT,
GetRequestContext()));
request_job->SetDMToken(dm_token_);
request_job->SetClientID(client_id_);
em::DeviceManagementRequest* request = request_job->GetRequest();
request->set_allocated_chrome_desktop_report_request(
chrome_desktop_report.release());
const DeviceManagementRequestJob::Callback job_callback =
base::Bind(&CloudPolicyClient::OnReportUploadCompleted,
weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback);
request_jobs_.push_back(std::move(request_job));
request_jobs_.back()->Start(job_callback);
}
void CloudPolicyClient::UploadAppInstallReport(
const em::AppInstallReportRequest* app_install_report,
const StatusCallback& callback) {
CHECK(is_registered());
DCHECK(app_install_report);
std::unique_ptr<DeviceManagementRequestJob> request_job(service_->CreateJob(
DeviceManagementRequestJob::TYPE_UPLOAD_APP_INSTALL_REPORT,
GetRequestContext()));
request_job->SetDMToken(dm_token_);
request_job->SetClientID(client_id_);
*request_job->GetRequest()->mutable_app_install_report_request() =
*app_install_report;
const DeviceManagementRequestJob::Callback job_callback =
base::AdaptCallbackForRepeating(base::BindOnce(
&CloudPolicyClient::OnReportUploadCompleted,
weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback));
CancelAppInstallReportUpload();
app_install_report_request_job_ = request_job.get();
request_jobs_.push_back(std::move(request_job));
request_jobs_.back()->Start(job_callback);
}
void CloudPolicyClient::CancelAppInstallReportUpload() {
if (app_install_report_request_job_) {
RemoveJob(app_install_report_request_job_);
}
}
void CloudPolicyClient::FetchRemoteCommands(
std::unique_ptr<RemoteCommandJob::UniqueIDType> last_command_id,
const std::vector<em::RemoteCommandResult>& command_results,
const RemoteCommandCallback& callback) {
CHECK(is_registered());
std::unique_ptr<DeviceManagementRequestJob> request_job(service_->CreateJob(
DeviceManagementRequestJob::TYPE_REMOTE_COMMANDS, GetRequestContext()));
request_job->SetDMToken(dm_token_);
request_job->SetClientID(client_id_);
em::DeviceRemoteCommandRequest* const request =
request_job->GetRequest()->mutable_remote_command_request();
if (last_command_id)
request->set_last_command_unique_id(*last_command_id);
for (const auto& command_result : command_results)
*request->add_command_results() = command_result;
const DeviceManagementRequestJob::Callback job_callback =
base::Bind(&CloudPolicyClient::OnRemoteCommandsFetched,
weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback);
request_jobs_.push_back(std::move(request_job));
request_jobs_.back()->Start(job_callback);
}
void CloudPolicyClient::GetDeviceAttributeUpdatePermission(
const std::string &auth_token,
const CloudPolicyClient::StatusCallback& callback) {
CHECK(is_registered());
DCHECK(!auth_token.empty());
std::unique_ptr<DeviceManagementRequestJob> request_job(service_->CreateJob(
DeviceManagementRequestJob::TYPE_ATTRIBUTE_UPDATE_PERMISSION,
GetRequestContext()));
request_job->SetOAuthToken(auth_token);
request_job->SetClientID(client_id_);
request_job->GetRequest()->
mutable_device_attribute_update_permission_request();
const DeviceManagementRequestJob::Callback job_callback =
base::Bind(&CloudPolicyClient::OnDeviceAttributeUpdatePermissionCompleted,
weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback);
request_jobs_.push_back(std::move(request_job));
request_jobs_.back()->Start(job_callback);
}
void CloudPolicyClient::UpdateDeviceAttributes(
const std::string& auth_token,
const std::string& asset_id,
const std::string& location,
const CloudPolicyClient::StatusCallback& callback) {
CHECK(is_registered());
DCHECK(!auth_token.empty());
std::unique_ptr<DeviceManagementRequestJob> request_job(service_->CreateJob(
DeviceManagementRequestJob::TYPE_ATTRIBUTE_UPDATE, GetRequestContext()));
request_job->SetOAuthToken(auth_token);
request_job->SetClientID(client_id_);
em::DeviceAttributeUpdateRequest* request =
request_job->GetRequest()->mutable_device_attribute_update_request();
request->set_asset_id(asset_id);
request->set_location(location);
const DeviceManagementRequestJob::Callback job_callback =
base::Bind(&CloudPolicyClient::OnDeviceAttributeUpdated,
weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback);
request_jobs_.push_back(std::move(request_job));
request_jobs_.back()->Start(job_callback);
}
void CloudPolicyClient::RequestAvailableLicenses(
const std::string& auth_token,
const LicenseRequestCallback& callback) {
DCHECK(!auth_token.empty());
std::unique_ptr<DeviceManagementRequestJob> request_job(service_->CreateJob(
DeviceManagementRequestJob::TYPE_REQUEST_LICENSE_TYPES,
GetRequestContext()));
request_job->SetOAuthToken(auth_token);
request_job->GetRequest()->mutable_check_device_license_request();
const DeviceManagementRequestJob::Callback job_callback =
base::Bind(&CloudPolicyClient::OnAvailableLicensesRequested,
weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback);
request_jobs_.push_back(std::move(request_job));
request_jobs_.back()->Start(job_callback);
}
void CloudPolicyClient::UpdateGcmId(
const std::string& gcm_id,
const CloudPolicyClient::StatusCallback& callback) {
CHECK(is_registered());
std::unique_ptr<DeviceManagementRequestJob> request_job(service_->CreateJob(
DeviceManagementRequestJob::TYPE_GCM_ID_UPDATE, GetRequestContext()));
request_job->SetDMToken(dm_token_);
request_job->SetClientID(client_id_);
em::GcmIdUpdateRequest* const request =
request_job->GetRequest()->mutable_gcm_id_update_request();
request->set_gcm_id(gcm_id);
const DeviceManagementRequestJob::Callback job_callback =
base::Bind(&CloudPolicyClient::OnGcmIdUpdated,
weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback);
request_jobs_.push_back(std::move(request_job));
request_jobs_.back()->Start(job_callback);
}
void CloudPolicyClient::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void CloudPolicyClient::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void CloudPolicyClient::AddPolicyTypeToFetch(
const std::string& policy_type,
const std::string& settings_entity_id) {
types_to_fetch_.insert(std::make_pair(policy_type, settings_entity_id));
}
void CloudPolicyClient::RemovePolicyTypeToFetch(
const std::string& policy_type,
const std::string& settings_entity_id) {
types_to_fetch_.erase(std::make_pair(policy_type, settings_entity_id));
}
void CloudPolicyClient::SetStateKeysToUpload(
const std::vector<std::string>& keys) {
state_keys_to_upload_ = keys;
}
const em::PolicyFetchResponse* CloudPolicyClient::GetPolicyFor(
const std::string& policy_type,
const std::string& settings_entity_id) const {
auto it = responses_.find(std::make_pair(policy_type, settings_entity_id));
return it == responses_.end() ? nullptr : it->second.get();
}
scoped_refptr<net::URLRequestContextGetter>
CloudPolicyClient::GetRequestContext() {
return request_context_;
}
scoped_refptr<network::SharedURLLoaderFactory>
CloudPolicyClient::GetURLLoaderFactory() {
return url_loader_factory_;
}
int CloudPolicyClient::GetActiveRequestCountForTest() const {
return request_jobs_.size();
}
void CloudPolicyClient::UploadCertificate(
const std::string& certificate_data,
em::DeviceCertUploadRequest::CertificateType certificate_type,
const CloudPolicyClient::StatusCallback& callback) {
CHECK(is_registered());
std::unique_ptr<DeviceManagementRequestJob> request_job(
service_->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_CERTIFICATE,
GetRequestContext()));
request_job->SetDMToken(dm_token_);
request_job->SetClientID(client_id_);
em::DeviceManagementRequest* request = request_job->GetRequest();
em::DeviceCertUploadRequest* upload_request =
request->mutable_cert_upload_request();
upload_request->set_device_certificate(certificate_data);
upload_request->set_certificate_type(certificate_type);
const DeviceManagementRequestJob::Callback job_callback = base::BindRepeating(
&CloudPolicyClient::OnCertificateUploadCompleted,
weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback);
request_jobs_.push_back(std::move(request_job));
request_jobs_.back()->Start(job_callback);
}
void CloudPolicyClient::OnRetryRegister(DeviceManagementRequestJob* job) {
DCHECK_EQ(policy_fetch_request_job_.get(), job);
// If the initial request managed to get to the server but the response didn't
// arrive at the client then retrying with the same client ID will fail.
// Set the re-registration flag so that the server accepts it.
// If the server hasn't seen the client ID before then it will also accept
// the re-registration.
job->GetRequest()->mutable_register_request()->set_reregister(true);
}
void CloudPolicyClient::OnRegisterCompleted(
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
if (status == DM_STATUS_SUCCESS &&
(!response.has_register_response() ||
!response.register_response().has_device_management_token())) {
LOG(WARNING) << "Invalid registration response.";
status = DM_STATUS_RESPONSE_DECODING_ERROR;
}
status_ = status;
if (status == DM_STATUS_SUCCESS) {
dm_token_ = response.register_response().device_management_token();
if (response.register_response().has_configuration_seed()) {
configuration_seed_ = base::DictionaryValue::From(base::JSONReader::Read(
response.register_response().configuration_seed(),
base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS));
if (!configuration_seed_)
LOG(ERROR) << "Failed to parse configuration seed";
}
DVLOG(1) << "Client registration complete - DMToken = " << dm_token_;
// Device mode is only relevant for device policy really, it's the
// responsibility of the consumer of the field to check validity.
device_mode_ = DEVICE_MODE_NOT_SET;
if (response.register_response().has_enrollment_type()) {
device_mode_ = TranslateProtobufDeviceMode(
response.register_response().enrollment_type());
}
if (device_dm_token_callback_) {
std::vector<std::string> user_affiliation_ids(
response.register_response().user_affiliation_ids().begin(),
response.register_response().user_affiliation_ids().end());
device_dm_token_ = device_dm_token_callback_.Run(user_affiliation_ids);
}
NotifyRegistrationStateChanged();
} else {
NotifyClientError();
}
}
void CloudPolicyClient::OnFetchRobotAuthCodesCompleted(
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
if (status == DM_STATUS_SUCCESS &&
(!response.has_service_api_access_response())) {
LOG(WARNING) << "Invalid service api access response.";
status = DM_STATUS_RESPONSE_DECODING_ERROR;
}
status_ = status;
if (status == DM_STATUS_SUCCESS) {
robot_api_auth_code_ = response.service_api_access_response().auth_code();
DVLOG(1) << "Device robot account auth code fetch complete - code = "
<< robot_api_auth_code_;
NotifyRobotAuthCodesFetched();
} else {
NotifyClientError();
}
}
void CloudPolicyClient::OnPolicyFetchCompleted(
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
if (status == DM_STATUS_SUCCESS) {
if (!response.has_policy_response() ||
response.policy_response().response_size() == 0) {
LOG(WARNING) << "Empty policy response.";
status = DM_STATUS_RESPONSE_DECODING_ERROR;
}
}
status_ = status;
if (status == DM_STATUS_SUCCESS) {
const em::DevicePolicyResponse& policy_response =
response.policy_response();
responses_.clear();
for (int i = 0; i < policy_response.response_size(); ++i) {
const em::PolicyFetchResponse& response = policy_response.response(i);
em::PolicyData policy_data;
if (!policy_data.ParseFromString(response.policy_data()) ||
!policy_data.IsInitialized() ||
!policy_data.has_policy_type()) {
LOG(WARNING) << "Invalid PolicyData received, ignoring";
continue;
}
const std::string& type = policy_data.policy_type();
std::string entity_id;
if (policy_data.has_settings_entity_id())
entity_id = policy_data.settings_entity_id();
std::pair<std::string, std::string> key(type, entity_id);
if (base::ContainsKey(responses_, key)) {
LOG(WARNING) << "Duplicate PolicyFetchResponse for type: "
<< type << ", entity: " << entity_id << ", ignoring";
continue;
}
responses_[key] = std::make_unique<em::PolicyFetchResponse>(response);
}
state_keys_to_upload_.clear();
NotifyPolicyFetched();
} else {
NotifyClientError();
}
}
void CloudPolicyClient::OnUnregisterCompleted(
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
if (status == DM_STATUS_SUCCESS && !response.has_unregister_response()) {
// Assume unregistration has succeeded either way.
LOG(WARNING) << "Empty unregistration response.";
}
status_ = status;
if (status == DM_STATUS_SUCCESS) {
dm_token_.clear();
// Cancel all outstanding jobs.
request_jobs_.clear();
app_install_report_request_job_ = nullptr;
device_dm_token_.clear();
NotifyRegistrationStateChanged();
} else {
NotifyClientError();
}
}
void CloudPolicyClient::OnCertificateUploadCompleted(
const DeviceManagementRequestJob* job,
const CloudPolicyClient::StatusCallback& callback,
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
bool success = true;
status_ = status;
if (status != DM_STATUS_SUCCESS) {
success = false;
NotifyClientError();
} else if (!response.has_cert_upload_response()) {
LOG(WARNING) << "Empty upload certificate response.";
success = false;
}
callback.Run(success);
// Must call RemoveJob() last, because it frees |callback|.
RemoveJob(job);
}
void CloudPolicyClient::OnDeviceAttributeUpdatePermissionCompleted(
const DeviceManagementRequestJob* job,
const CloudPolicyClient::StatusCallback& callback,
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
bool success = false;
if (status == DM_STATUS_SUCCESS &&
!response.has_device_attribute_update_permission_response()) {
LOG(WARNING) << "Invalid device attribute update permission response.";
status = DM_STATUS_RESPONSE_DECODING_ERROR;
}
status_ = status;
if (status == DM_STATUS_SUCCESS &&
response.device_attribute_update_permission_response().has_result() &&
response.device_attribute_update_permission_response().result() ==
em::DeviceAttributeUpdatePermissionResponse::ATTRIBUTE_UPDATE_ALLOWED) {
success = true;
}
callback.Run(success);
RemoveJob(job);
}
void CloudPolicyClient::OnDeviceAttributeUpdated(
const DeviceManagementRequestJob* job,
const CloudPolicyClient::StatusCallback& callback,
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
bool success = false;
if (status == DM_STATUS_SUCCESS &&
!response.has_device_attribute_update_response()) {
LOG(WARNING) << "Invalid device attribute update response.";
status = DM_STATUS_RESPONSE_DECODING_ERROR;
}
status_ = status;
if (status == DM_STATUS_SUCCESS &&
response.device_attribute_update_response().has_result() &&
response.device_attribute_update_response().result() ==
em::DeviceAttributeUpdateResponse::ATTRIBUTE_UPDATE_SUCCESS) {
success = true;
}
callback.Run(success);
RemoveJob(job);
}
void CloudPolicyClient::OnAvailableLicensesRequested(
const DeviceManagementRequestJob* job,
const CloudPolicyClient::LicenseRequestCallback& callback,
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
CloudPolicyClient::LicenseMap licenses;
if (status != DM_STATUS_SUCCESS) {
LOG(WARNING) << "Could not get available license types";
status_ = status;
callback.Run(false /* success */, licenses);
RemoveJob(job);
return;
}
if (!response.has_check_device_license_response()) {
LOG(WARNING) << "Invalid license request response.";
status_ = DM_STATUS_RESPONSE_DECODING_ERROR;
callback.Run(false /* success */, licenses);
RemoveJob(job);
return;
}
status_ = status;
const em::CheckDeviceLicenseResponse& license_response =
response.check_device_license_response();
if (license_response.has_license_selection_mode() &&
(license_response.license_selection_mode() ==
em::CheckDeviceLicenseResponse::USER_SELECTION)) {
ExtractLicenseMap(license_response, licenses);
}
callback.Run(true /* success */, licenses);
RemoveJob(job);
}
void CloudPolicyClient::RemoveJob(const DeviceManagementRequestJob* job) {
if (app_install_report_request_job_ == job) {
app_install_report_request_job_ = nullptr;
}
for (auto it = request_jobs_.begin(); it != request_jobs_.end(); ++it) {
if (it->get() == job) {
request_jobs_.erase(it);
return;
}
}
// This job was already deleted from our list, somehow. This shouldn't
// happen since deleting the job should cancel the callback.
NOTREACHED();
}
void CloudPolicyClient::OnReportUploadCompleted(
const DeviceManagementRequestJob* job,
const CloudPolicyClient::StatusCallback& callback,
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
status_ = status;
if (status != DM_STATUS_SUCCESS)
NotifyClientError();
callback.Run(status == DM_STATUS_SUCCESS);
// Must call RemoveJob() last, because it frees |callback|.
RemoveJob(job);
}
void CloudPolicyClient::OnRemoteCommandsFetched(
const DeviceManagementRequestJob* job,
const RemoteCommandCallback& callback,
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
std::vector<em::RemoteCommand> commands;
if (status == DM_STATUS_SUCCESS) {
if (response.has_remote_command_response()) {
for (const auto& command : response.remote_command_response().commands())
commands.push_back(command);
} else {
status = DM_STATUS_RESPONSE_DECODING_ERROR;
}
}
callback.Run(status, commands);
// Must call RemoveJob() last, because it frees |callback|.
RemoveJob(job);
}
void CloudPolicyClient::OnGcmIdUpdated(
const DeviceManagementRequestJob* job,
const StatusCallback& callback,
DeviceManagementStatus status,
int net_error,
const em::DeviceManagementResponse& response) {
status_ = status;
if (status != DM_STATUS_SUCCESS)
NotifyClientError();
callback.Run(status == DM_STATUS_SUCCESS);
RemoveJob(job);
}
void CloudPolicyClient::NotifyPolicyFetched() {
for (auto& observer : observers_)
observer.OnPolicyFetched(this);
}
void CloudPolicyClient::NotifyRegistrationStateChanged() {
for (auto& observer : observers_)
observer.OnRegistrationStateChanged(this);
}
void CloudPolicyClient::NotifyRobotAuthCodesFetched() {
for (auto& observer : observers_)
observer.OnRobotAuthCodesFetched(this);
}
void CloudPolicyClient::NotifyClientError() {
for (auto& observer : observers_)
observer.OnClientError(this);
}
} // namespace policy