Home | History | Annotate | Download | only in cloud
      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/policy/cloud/cloud_policy_client.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/guid.h"
      9 #include "base/logging.h"
     10 #include "base/stl_util.h"
     11 #include "chrome/browser/policy/cloud/device_management_service.h"
     12 #include "google_apis/gaia/gaia_constants.h"
     13 #include "google_apis/gaia/gaia_urls.h"
     14 
     15 namespace em = enterprise_management;
     16 
     17 namespace policy {
     18 
     19 namespace {
     20 
     21 // Translates the DeviceRegisterResponse::DeviceMode |mode| to the enum used
     22 // internally to represent different device modes.
     23 DeviceMode TranslateProtobufDeviceMode(
     24     em::DeviceRegisterResponse::DeviceMode mode) {
     25   switch (mode) {
     26     case em::DeviceRegisterResponse::ENTERPRISE:
     27       return DEVICE_MODE_ENTERPRISE;
     28     case em::DeviceRegisterResponse::RETAIL:
     29       return DEVICE_MODE_RETAIL_KIOSK;
     30   }
     31   LOG(ERROR) << "Unknown enrollment mode in registration response: " << mode;
     32   return DEVICE_MODE_NOT_SET;
     33 }
     34 
     35 bool IsChromePolicy(const std::string& type) {
     36   return type == dm_protocol::kChromeDevicePolicyType ||
     37          type == GetChromeUserPolicyType();
     38 }
     39 
     40 }  // namespace
     41 
     42 CloudPolicyClient::Observer::~Observer() {}
     43 
     44 void CloudPolicyClient::Observer::OnRobotAuthCodesFetched(
     45     CloudPolicyClient* client) {}
     46 
     47 CloudPolicyClient::StatusProvider::~StatusProvider() {}
     48 
     49 CloudPolicyClient::CloudPolicyClient(const std::string& machine_id,
     50                                      const std::string& machine_model,
     51                                      UserAffiliation user_affiliation,
     52                                      StatusProvider* status_provider,
     53                                      DeviceManagementService* service)
     54     : machine_id_(machine_id),
     55       machine_model_(machine_model),
     56       user_affiliation_(user_affiliation),
     57       device_mode_(DEVICE_MODE_NOT_SET),
     58       submit_machine_id_(false),
     59       public_key_version_(-1),
     60       public_key_version_valid_(false),
     61       invalidation_version_(0),
     62       fetched_invalidation_version_(0),
     63       service_(service),                  // Can be NULL for unit tests.
     64       status_provider_(status_provider),  // Can be NULL for unit tests.
     65       status_(DM_STATUS_SUCCESS) {
     66 }
     67 
     68 CloudPolicyClient::~CloudPolicyClient() {
     69   STLDeleteValues(&responses_);
     70 }
     71 
     72 void CloudPolicyClient::SetupRegistration(const std::string& dm_token,
     73                                           const std::string& client_id) {
     74   DCHECK(!dm_token.empty());
     75   DCHECK(!client_id.empty());
     76   DCHECK(!is_registered());
     77 
     78   dm_token_ = dm_token;
     79   client_id_ = client_id;
     80   request_job_.reset();
     81   STLDeleteValues(&responses_);
     82 
     83   NotifyRegistrationStateChanged();
     84 }
     85 
     86 void CloudPolicyClient::Register(em::DeviceRegisterRequest::Type type,
     87                                  const std::string& auth_token,
     88                                  const std::string& client_id,
     89                                  bool is_auto_enrollement,
     90                                  const std::string& requisition) {
     91   DCHECK(service_);
     92   DCHECK(!auth_token.empty());
     93   DCHECK(!is_registered());
     94 
     95   if (client_id.empty()) {
     96     // Generate a new client ID. This is intentionally done on each new
     97     // registration request in order to preserve privacy. Reusing IDs would mean
     98     // the server could track clients by their registration attempts.
     99     client_id_ = base::GenerateGUID();
    100   } else {
    101     client_id_ = client_id;
    102   }
    103 
    104   request_job_.reset(
    105       service_->CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION));
    106   request_job_->SetOAuthToken(auth_token);
    107   request_job_->SetClientID(client_id_);
    108 
    109   em::DeviceRegisterRequest* request =
    110       request_job_->GetRequest()->mutable_register_request();
    111   if (!client_id.empty())
    112     request->set_reregister(true);
    113   request->set_type(type);
    114   if (!machine_id_.empty())
    115     request->set_machine_id(machine_id_);
    116   if (!machine_model_.empty())
    117     request->set_machine_model(machine_model_);
    118   if (is_auto_enrollement)
    119     request->set_auto_enrolled(true);
    120   if (!requisition.empty())
    121     request->set_requisition(requisition);
    122 
    123   request_job_->SetRetryCallback(
    124       base::Bind(&CloudPolicyClient::OnRetryRegister, base::Unretained(this)));
    125 
    126   request_job_->Start(base::Bind(&CloudPolicyClient::OnRegisterCompleted,
    127                                  base::Unretained(this)));
    128 }
    129 
    130 void CloudPolicyClient::SetInvalidationInfo(
    131     int64 version,
    132     const std::string& payload) {
    133   invalidation_version_ = version;
    134   invalidation_payload_ = payload;
    135 }
    136 
    137 void CloudPolicyClient::FetchPolicy() {
    138   CHECK(is_registered());
    139   CHECK(!namespaces_to_fetch_.empty());
    140 
    141   request_job_.reset(
    142       service_->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH));
    143   request_job_->SetDMToken(dm_token_);
    144   request_job_->SetClientID(client_id_);
    145   request_job_->SetUserAffiliation(user_affiliation_);
    146 
    147   em::DeviceManagementRequest* request = request_job_->GetRequest();
    148 
    149   // Build policy fetch requests.
    150   em::DevicePolicyRequest* policy_request = request->mutable_policy_request();
    151   for (NamespaceSet::iterator it = namespaces_to_fetch_.begin();
    152        it != namespaces_to_fetch_.end(); ++it) {
    153     em::PolicyFetchRequest* fetch_request = policy_request->add_request();
    154     fetch_request->set_policy_type(it->first);
    155     if (!it->second.empty())
    156       fetch_request->set_settings_entity_id(it->second);
    157 
    158 #if defined(OS_CHROMEOS)
    159     // All policy types on ChromeOS ask for a signed policy blob.
    160     fetch_request->set_signature_type(em::PolicyFetchRequest::SHA1_RSA);
    161 #else
    162     // Don't request signed blobs for desktop policy.
    163     fetch_request->set_signature_type(em::PolicyFetchRequest::NONE);
    164 #endif
    165     if (public_key_version_valid_)
    166       fetch_request->set_public_key_version(public_key_version_);
    167 
    168     // These fields are included only in requests for chrome policy.
    169     if (IsChromePolicy(it->first)) {
    170       if (submit_machine_id_ && !machine_id_.empty())
    171         fetch_request->set_machine_id(machine_id_);
    172       if (!last_policy_timestamp_.is_null()) {
    173         base::TimeDelta timestamp(
    174             last_policy_timestamp_ - base::Time::UnixEpoch());
    175         fetch_request->set_timestamp(timestamp.InMilliseconds());
    176       }
    177       if (!invalidation_payload_.empty()) {
    178         fetch_request->set_invalidation_version(invalidation_version_);
    179         fetch_request->set_invalidation_payload(invalidation_payload_);
    180       }
    181     }
    182   }
    183 
    184   // Add status data.
    185   if (status_provider_) {
    186     if (!status_provider_->GetDeviceStatus(
    187             request->mutable_device_status_report_request())) {
    188       request->clear_device_status_report_request();
    189     }
    190     if (!status_provider_->GetSessionStatus(
    191             request->mutable_session_status_report_request())) {
    192       request->clear_session_status_report_request();
    193     }
    194   }
    195 
    196   // Set the fetched invalidation version to the latest invalidation version
    197   // since it is now the invalidation version used for the latest fetch.
    198   fetched_invalidation_version_ = invalidation_version_;
    199 
    200   // Fire the job.
    201   request_job_->Start(base::Bind(&CloudPolicyClient::OnPolicyFetchCompleted,
    202                                  base::Unretained(this)));
    203 }
    204 
    205 void CloudPolicyClient::FetchRobotAuthCodes(const std::string& auth_token) {
    206   CHECK(is_registered());
    207   DCHECK(!auth_token.empty());
    208 
    209   request_job_.reset(service_->CreateJob(
    210       DeviceManagementRequestJob::TYPE_API_AUTH_CODE_FETCH));
    211   // The credentials of a domain user are needed in order to mint a new OAuth2
    212   // authorization token for the robot account.
    213   request_job_->SetOAuthToken(auth_token);
    214   request_job_->SetDMToken(dm_token_);
    215   request_job_->SetClientID(client_id_);
    216 
    217   em::DeviceServiceApiAccessRequest* request =
    218       request_job_->GetRequest()->mutable_service_api_access_request();
    219   request->set_oauth2_client_id(
    220       GaiaUrls::GetInstance()->oauth2_chrome_client_id());
    221   request->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope);
    222 
    223   request_job_->Start(
    224       base::Bind(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
    225                  base::Unretained(this)));
    226 }
    227 
    228 void CloudPolicyClient::Unregister() {
    229   DCHECK(service_);
    230   request_job_.reset(
    231       service_->CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION));
    232   request_job_->SetDMToken(dm_token_);
    233   request_job_->SetClientID(client_id_);
    234   request_job_->GetRequest()->mutable_unregister_request();
    235   request_job_->Start(base::Bind(&CloudPolicyClient::OnUnregisterCompleted,
    236                                  base::Unretained(this)));
    237 }
    238 
    239 void CloudPolicyClient::UploadCertificate(
    240     const std::string& certificate_data,
    241     const CloudPolicyClient::StatusCallback& callback) {
    242   CHECK(is_registered());
    243   request_job_.reset(
    244       service_->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_CERTIFICATE));
    245   request_job_->SetDMToken(dm_token_);
    246   request_job_->SetClientID(client_id_);
    247 
    248   em::DeviceManagementRequest* request = request_job_->GetRequest();
    249   request->mutable_cert_upload_request()->set_device_certificate(
    250       certificate_data);
    251 
    252   DeviceManagementRequestJob::Callback job_callback = base::Bind(
    253       &CloudPolicyClient::OnCertificateUploadCompleted,
    254       base::Unretained(this),
    255       callback);
    256   request_job_->Start(job_callback);
    257 }
    258 
    259 void CloudPolicyClient::AddObserver(Observer* observer) {
    260   observers_.AddObserver(observer);
    261 }
    262 
    263 void CloudPolicyClient::RemoveObserver(Observer* observer) {
    264   observers_.RemoveObserver(observer);
    265 }
    266 
    267 void CloudPolicyClient::AddNamespaceToFetch(const PolicyNamespaceKey& key) {
    268   namespaces_to_fetch_.insert(key);
    269 }
    270 
    271 void CloudPolicyClient::RemoveNamespaceToFetch(const PolicyNamespaceKey& key) {
    272   namespaces_to_fetch_.erase(key);
    273 }
    274 
    275 const em::PolicyFetchResponse* CloudPolicyClient::GetPolicyFor(
    276     const PolicyNamespaceKey& key) const {
    277   ResponseMap::const_iterator it = responses_.find(key);
    278   return it == responses_.end() ? NULL : it->second;
    279 }
    280 
    281 void CloudPolicyClient::OnRetryRegister(DeviceManagementRequestJob* job) {
    282   DCHECK_EQ(request_job_.get(), job);
    283   // If the initial request managed to get to the server but the response didn't
    284   // arrive at the client then retrying with the same client ID will fail.
    285   // Set the re-registration flag so that the server accepts it.
    286   // If the server hasn't seen the client ID before then it will also accept
    287   // the re-registration.
    288   job->GetRequest()->mutable_register_request()->set_reregister(true);
    289 }
    290 
    291 void CloudPolicyClient::OnRegisterCompleted(
    292     DeviceManagementStatus status,
    293     int net_error,
    294     const em::DeviceManagementResponse& response) {
    295   if (status == DM_STATUS_SUCCESS &&
    296       (!response.has_register_response() ||
    297        !response.register_response().has_device_management_token())) {
    298     LOG(WARNING) << "Invalid registration response.";
    299     status = DM_STATUS_RESPONSE_DECODING_ERROR;
    300   }
    301 
    302   status_ = status;
    303   if (status == DM_STATUS_SUCCESS) {
    304     dm_token_ = response.register_response().device_management_token();
    305     DVLOG(1) << "Client registration complete - DMToken = " << dm_token_;
    306 
    307     // Device mode is only relevant for device policy really, it's the
    308     // responsibility of the consumer of the field to check validity.
    309     device_mode_ = DEVICE_MODE_NOT_SET;
    310     if (response.register_response().has_enrollment_type()) {
    311       device_mode_ = TranslateProtobufDeviceMode(
    312           response.register_response().enrollment_type());
    313     }
    314 
    315     NotifyRegistrationStateChanged();
    316   } else {
    317     NotifyClientError();
    318   }
    319 }
    320 
    321 void CloudPolicyClient::OnFetchRobotAuthCodesCompleted(
    322     DeviceManagementStatus status,
    323     int net_error,
    324     const em::DeviceManagementResponse& response) {
    325   if (status == DM_STATUS_SUCCESS &&
    326       (!response.has_service_api_access_response() ||
    327        response.service_api_access_response().auth_code().empty())) {
    328     LOG(WARNING) << "Invalid service api access response.";
    329     status = DM_STATUS_RESPONSE_DECODING_ERROR;
    330   }
    331 
    332   status_ = status;
    333   if (status == DM_STATUS_SUCCESS) {
    334     robot_api_auth_code_ = response.service_api_access_response().auth_code();
    335     DVLOG(1) << "Device robot account auth code fetch complete - code = "
    336              << robot_api_auth_code_;
    337 
    338     NotifyRobotAuthCodesFetched();
    339   } else {
    340     NotifyClientError();
    341   }
    342 }
    343 
    344 void CloudPolicyClient::OnPolicyFetchCompleted(
    345     DeviceManagementStatus status,
    346     int net_error,
    347     const em::DeviceManagementResponse& response) {
    348   if (status == DM_STATUS_SUCCESS) {
    349     if (!response.has_policy_response() ||
    350         response.policy_response().response_size() == 0) {
    351       LOG(WARNING) << "Empty policy response.";
    352       status = DM_STATUS_RESPONSE_DECODING_ERROR;
    353     }
    354   }
    355 
    356   status_ = status;
    357   if (status == DM_STATUS_SUCCESS) {
    358     const em::DevicePolicyResponse& policy_response =
    359         response.policy_response();
    360     STLDeleteValues(&responses_);
    361     for (int i = 0; i < policy_response.response_size(); ++i) {
    362       const em::PolicyFetchResponse& response = policy_response.response(i);
    363       em::PolicyData policy_data;
    364       if (!policy_data.ParseFromString(response.policy_data()) ||
    365           !policy_data.IsInitialized() ||
    366           !policy_data.has_policy_type()) {
    367         LOG(WARNING) << "Invalid PolicyData received, ignoring";
    368         continue;
    369       }
    370       const std::string& type = policy_data.policy_type();
    371       std::string entity_id;
    372       if (policy_data.has_settings_entity_id())
    373         entity_id = policy_data.settings_entity_id();
    374       PolicyNamespaceKey key(type, entity_id);
    375       if (ContainsKey(responses_, key)) {
    376         LOG(WARNING) << "Duplicate PolicyFetchResponse for type: "
    377             << type << ", entity: " << entity_id << ", ignoring";
    378         continue;
    379       }
    380       responses_[key] = new em::PolicyFetchResponse(response);
    381     }
    382     if (status_provider_)
    383       status_provider_->OnSubmittedSuccessfully();
    384     NotifyPolicyFetched();
    385   } else {
    386     NotifyClientError();
    387   }
    388 }
    389 
    390 void CloudPolicyClient::OnUnregisterCompleted(
    391     DeviceManagementStatus status,
    392     int net_error,
    393     const em::DeviceManagementResponse& response) {
    394   if (status == DM_STATUS_SUCCESS && !response.has_unregister_response()) {
    395     // Assume unregistration has succeeded either way.
    396     LOG(WARNING) << "Empty unregistration response.";
    397   }
    398 
    399   status_ = status;
    400   if (status == DM_STATUS_SUCCESS) {
    401     dm_token_.clear();
    402     NotifyRegistrationStateChanged();
    403   } else {
    404     NotifyClientError();
    405   }
    406 }
    407 
    408 void CloudPolicyClient::OnCertificateUploadCompleted(
    409     const CloudPolicyClient::StatusCallback& callback,
    410     DeviceManagementStatus status,
    411     int net_error,
    412     const enterprise_management::DeviceManagementResponse& response) {
    413   if (status == DM_STATUS_SUCCESS && !response.has_cert_upload_response()) {
    414     LOG(WARNING) << "Empty upload certificate response.";
    415     callback.Run(false);
    416     return;
    417   }
    418 
    419   status_ = status;
    420   if (status != DM_STATUS_SUCCESS) {
    421     NotifyClientError();
    422     callback.Run(false);
    423     return;
    424   }
    425   callback.Run(true);
    426 }
    427 
    428 void CloudPolicyClient::NotifyPolicyFetched() {
    429   FOR_EACH_OBSERVER(Observer, observers_, OnPolicyFetched(this));
    430 }
    431 
    432 void CloudPolicyClient::NotifyRegistrationStateChanged() {
    433   FOR_EACH_OBSERVER(Observer, observers_, OnRegistrationStateChanged(this));
    434 }
    435 
    436 void CloudPolicyClient::NotifyRobotAuthCodesFetched() {
    437   FOR_EACH_OBSERVER(Observer, observers_, OnRobotAuthCodesFetched(this));
    438 }
    439 
    440 void CloudPolicyClient::NotifyClientError() {
    441   FOR_EACH_OBSERVER(Observer, observers_, OnClientError(this));
    442 }
    443 
    444 }  // namespace policy
    445