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