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