Home | History | Annotate | Download | only in policy
      1 // Copyright (c) 2011 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/device_management_backend_impl.h"
      6 
      7 #include <utility>
      8 #include <vector>
      9 
     10 #if defined(OS_POSIX) && !defined(OS_MACOSX)
     11 #include <sys/utsname.h>
     12 #endif
     13 
     14 #include "base/stringprintf.h"
     15 #include "base/sys_info.h"
     16 #include "chrome/browser/policy/device_management_service.h"
     17 #include "chrome/common/chrome_version_info.h"
     18 #include "net/base/escape.h"
     19 #include "net/url_request/url_request_status.h"
     20 
     21 #if defined(OS_CHROMEOS)
     22 #include "chrome/browser/chromeos/system_access.h"
     23 #endif
     24 
     25 namespace policy {
     26 
     27 // Name constants for URL query parameters.
     28 const char DeviceManagementBackendImpl::kParamRequest[] = "request";
     29 const char DeviceManagementBackendImpl::kParamDeviceType[] = "devicetype";
     30 const char DeviceManagementBackendImpl::kParamAppType[] = "apptype";
     31 const char DeviceManagementBackendImpl::kParamDeviceID[] = "deviceid";
     32 const char DeviceManagementBackendImpl::kParamAgent[] = "agent";
     33 const char DeviceManagementBackendImpl::kParamPlatform[] = "platform";
     34 
     35 // String constants for the device and app type we report to the server.
     36 const char DeviceManagementBackendImpl::kValueRequestRegister[] = "register";
     37 const char DeviceManagementBackendImpl::kValueRequestUnregister[] =
     38     "unregister";
     39 const char DeviceManagementBackendImpl::kValueRequestPolicy[] = "policy";
     40 const char DeviceManagementBackendImpl::kValueDeviceType[] = "2";
     41 const char DeviceManagementBackendImpl::kValueAppType[] = "Chrome";
     42 
     43 namespace {
     44 
     45 const char kValueAgent[] = "%s %s(%s)";
     46 const char kValuePlatform[] = "%s|%s|%s";
     47 
     48 const char kPostContentType[] = "application/protobuf";
     49 
     50 const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth=";
     51 const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token=";
     52 
     53 // HTTP Error Codes of the DM Server with their concrete meinings in the context
     54 // of the DM Server communication.
     55 const int kSuccess = 200;
     56 const int kInvalidArgument = 400;
     57 const int kInvalidAuthCookieOrDMToken = 401;
     58 const int kDeviceManagementNotAllowed = 403;
     59 const int kInvalidURL = 404; // This error is not coming from the GFE.
     60 const int kPendingApproval = 491;
     61 const int kInternalServerError = 500;
     62 const int kServiceUnavailable = 503;
     63 const int kDeviceNotFound = 901;
     64 const int kPolicyNotFound = 902; // This error is not sent as HTTP status code.
     65 
     66 #if defined(OS_CHROMEOS)
     67 // Machine info keys.
     68 const char kMachineInfoHWClass[] = "hardware_class";
     69 const char kMachineInfoBoard[] = "CHROMEOS_RELEASE_BOARD";
     70 #endif
     71 
     72 }  // namespace
     73 
     74 // Helper class for URL query parameter encoding/decoding.
     75 class URLQueryParameters {
     76  public:
     77   URLQueryParameters() {}
     78 
     79   // Add a query parameter.
     80   void Put(const std::string& name, const std::string& value);
     81 
     82   // Produce the query string, taking care of properly encoding and assembling
     83   // the names and values.
     84   std::string Encode();
     85 
     86  private:
     87   typedef std::vector<std::pair<std::string, std::string> > ParameterMap;
     88   ParameterMap params_;
     89 
     90   DISALLOW_COPY_AND_ASSIGN(URLQueryParameters);
     91 };
     92 
     93 void URLQueryParameters::Put(const std::string& name,
     94                              const std::string& value) {
     95   params_.push_back(std::make_pair(name, value));
     96 }
     97 
     98 std::string URLQueryParameters::Encode() {
     99   std::string result;
    100   for (ParameterMap::const_iterator entry(params_.begin());
    101        entry != params_.end();
    102        ++entry) {
    103     if (entry != params_.begin())
    104       result += '&';
    105     result += EscapeQueryParamValue(entry->first, true);
    106     result += '=';
    107     result += EscapeQueryParamValue(entry->second, true);
    108   }
    109   return result;
    110 }
    111 
    112 // A base class containing the common code for the jobs created by the backend
    113 // implementation. Subclasses provide custom code for handling actual register,
    114 // unregister, and policy jobs.
    115 class DeviceManagementJobBase
    116     : public DeviceManagementService::DeviceManagementJob {
    117  public:
    118   virtual ~DeviceManagementJobBase() {}
    119 
    120   // DeviceManagementJob overrides:
    121   virtual void HandleResponse(const net::URLRequestStatus& status,
    122                               int response_code,
    123                               const ResponseCookies& cookies,
    124                               const std::string& data);
    125   virtual GURL GetURL(const std::string& server_url);
    126   virtual void ConfigureRequest(URLFetcher* fetcher);
    127 
    128  protected:
    129   // Constructs a device management job running for the given backend.
    130   DeviceManagementJobBase(DeviceManagementBackendImpl* backend_impl,
    131                           const std::string& request_type,
    132                           const std::string& device_id)
    133       : backend_impl_(backend_impl) {
    134     query_params_.Put(DeviceManagementBackendImpl::kParamRequest, request_type);
    135     query_params_.Put(DeviceManagementBackendImpl::kParamDeviceType,
    136                       DeviceManagementBackendImpl::kValueDeviceType);
    137     query_params_.Put(DeviceManagementBackendImpl::kParamAppType,
    138                       DeviceManagementBackendImpl::kValueAppType);
    139     query_params_.Put(DeviceManagementBackendImpl::kParamDeviceID, device_id);
    140     query_params_.Put(DeviceManagementBackendImpl::kParamAgent,
    141                       DeviceManagementBackendImpl::GetAgentString());
    142     query_params_.Put(DeviceManagementBackendImpl::kParamPlatform,
    143                       DeviceManagementBackendImpl::GetPlatformString());
    144   }
    145 
    146   void SetQueryParam(const std::string& name, const std::string& value) {
    147     query_params_.Put(name, value);
    148   }
    149 
    150   void SetAuthToken(const std::string& auth_token) {
    151     auth_token_ = auth_token;
    152   }
    153 
    154   void SetDeviceManagementToken(const std::string& device_management_token) {
    155     device_management_token_ = device_management_token;
    156   }
    157 
    158   void SetPayload(const em::DeviceManagementRequest& request) {
    159     if (!request.SerializeToString(&payload_)) {
    160       NOTREACHED();
    161       LOG(ERROR) << "Failed to serialize request.";
    162     }
    163   }
    164 
    165  private:
    166   // Implemented by subclasses to handle decoded responses and errors.
    167   virtual void OnResponse(
    168       const em::DeviceManagementResponse& response) = 0;
    169   virtual void OnError(DeviceManagementBackend::ErrorCode error) = 0;
    170 
    171   // The backend this job is handling a request for.
    172   DeviceManagementBackendImpl* backend_impl_;
    173 
    174   // Query parameters.
    175   URLQueryParameters query_params_;
    176 
    177   // Auth token (if applicaple).
    178   std::string auth_token_;
    179 
    180   // Device management token (if applicable).
    181   std::string device_management_token_;
    182 
    183   // The payload.
    184   std::string payload_;
    185 
    186   DISALLOW_COPY_AND_ASSIGN(DeviceManagementJobBase);
    187 };
    188 
    189 void DeviceManagementJobBase::HandleResponse(
    190     const net::URLRequestStatus& status,
    191     int response_code,
    192     const ResponseCookies& cookies,
    193     const std::string& data) {
    194   // Delete ourselves when this is done.
    195   scoped_ptr<DeviceManagementJob> scoped_killer(this);
    196   backend_impl_->JobDone(this);
    197   backend_impl_ = NULL;
    198 
    199   if (status.status() != net::URLRequestStatus::SUCCESS) {
    200     OnError(DeviceManagementBackend::kErrorRequestFailed);
    201     return;
    202   }
    203 
    204   switch (response_code) {
    205     case kSuccess: {
    206       em::DeviceManagementResponse response;
    207       if (!response.ParseFromString(data)) {
    208         OnError(DeviceManagementBackend::kErrorResponseDecoding);
    209         return;
    210       }
    211       OnResponse(response);
    212       return;
    213     }
    214     case kInvalidArgument: {
    215       OnError(DeviceManagementBackend::kErrorRequestInvalid);
    216       return;
    217     }
    218     case kInvalidAuthCookieOrDMToken: {
    219       OnError(DeviceManagementBackend::kErrorServiceManagementTokenInvalid);
    220       return;
    221     }
    222     case kDeviceManagementNotAllowed: {
    223       OnError(DeviceManagementBackend::kErrorServiceManagementNotSupported);
    224       return;
    225     }
    226     case kPendingApproval: {
    227       OnError(DeviceManagementBackend::kErrorServiceActivationPending);
    228       return;
    229     }
    230     case kInvalidURL:
    231     case kInternalServerError:
    232     case kServiceUnavailable: {
    233       OnError(DeviceManagementBackend::kErrorTemporaryUnavailable);
    234       return;
    235     }
    236     case kDeviceNotFound: {
    237       OnError(DeviceManagementBackend::kErrorServiceDeviceNotFound);
    238       return;
    239     }
    240     case kPolicyNotFound: {
    241       OnError(DeviceManagementBackend::kErrorServicePolicyNotFound);
    242       break;
    243     }
    244     default: {
    245       VLOG(1) << "Unexpected HTTP status in response from DMServer : "
    246               << response_code << ".";
    247       // Handle all unknown 5xx HTTP error codes as temporary and any other
    248       // unknown error as one that needs more time to recover.
    249       if (response_code >= 500 && response_code <= 599)
    250         OnError(DeviceManagementBackend::kErrorTemporaryUnavailable);
    251       else
    252         OnError(DeviceManagementBackend::kErrorHttpStatus);
    253       return;
    254     }
    255   }
    256 }
    257 
    258 GURL DeviceManagementJobBase::GetURL(
    259     const std::string& server_url) {
    260   return GURL(server_url + '?' + query_params_.Encode());
    261 }
    262 
    263 void DeviceManagementJobBase::ConfigureRequest(URLFetcher* fetcher) {
    264   fetcher->set_upload_data(kPostContentType, payload_);
    265   std::string extra_headers;
    266   if (!auth_token_.empty())
    267     extra_headers += kServiceTokenAuthHeader + auth_token_ + "\n";
    268   if (!device_management_token_.empty())
    269     extra_headers += kDMTokenAuthHeader + device_management_token_ + "\n";
    270   fetcher->set_extra_request_headers(extra_headers);
    271 }
    272 
    273 // Handles device registration jobs.
    274 class DeviceManagementRegisterJob : public DeviceManagementJobBase {
    275  public:
    276   DeviceManagementRegisterJob(
    277       DeviceManagementBackendImpl* backend_impl,
    278       const std::string& auth_token,
    279       const std::string& device_id,
    280       const em::DeviceRegisterRequest& request,
    281       DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate)
    282       : DeviceManagementJobBase(
    283           backend_impl,
    284           DeviceManagementBackendImpl::kValueRequestRegister,
    285           device_id),
    286         delegate_(delegate) {
    287     SetAuthToken(auth_token);
    288     em::DeviceManagementRequest request_wrapper;
    289     request_wrapper.mutable_register_request()->CopyFrom(request);
    290     SetPayload(request_wrapper);
    291   }
    292   virtual ~DeviceManagementRegisterJob() {}
    293 
    294  private:
    295   // DeviceManagementJobBase overrides.
    296   virtual void OnError(DeviceManagementBackend::ErrorCode error) {
    297     delegate_->OnError(error);
    298   }
    299   virtual void OnResponse(const em::DeviceManagementResponse& response) {
    300     delegate_->HandleRegisterResponse(response.register_response());
    301   }
    302 
    303   DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate_;
    304 
    305   DISALLOW_COPY_AND_ASSIGN(DeviceManagementRegisterJob);
    306 };
    307 
    308 // Handles device unregistration jobs.
    309 class DeviceManagementUnregisterJob : public DeviceManagementJobBase {
    310  public:
    311   DeviceManagementUnregisterJob(
    312       DeviceManagementBackendImpl* backend_impl,
    313       const std::string& device_management_token,
    314       const std::string& device_id,
    315       const em::DeviceUnregisterRequest& request,
    316       DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate)
    317       : DeviceManagementJobBase(
    318           backend_impl,
    319           DeviceManagementBackendImpl::kValueRequestUnregister,
    320           device_id),
    321         delegate_(delegate) {
    322     SetDeviceManagementToken(device_management_token);
    323     em::DeviceManagementRequest request_wrapper;
    324     request_wrapper.mutable_unregister_request()->CopyFrom(request);
    325     SetPayload(request_wrapper);
    326   }
    327   virtual ~DeviceManagementUnregisterJob() {}
    328 
    329  private:
    330   // DeviceManagementJobBase overrides.
    331   virtual void OnError(DeviceManagementBackend::ErrorCode error) {
    332     delegate_->OnError(error);
    333   }
    334   virtual void OnResponse(const em::DeviceManagementResponse& response) {
    335     delegate_->HandleUnregisterResponse(response.unregister_response());
    336   }
    337 
    338   DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate_;
    339 
    340   DISALLOW_COPY_AND_ASSIGN(DeviceManagementUnregisterJob);
    341 };
    342 
    343 // Handles policy request jobs.
    344 class DeviceManagementPolicyJob : public DeviceManagementJobBase {
    345  public:
    346   DeviceManagementPolicyJob(
    347       DeviceManagementBackendImpl* backend_impl,
    348       const std::string& device_management_token,
    349       const std::string& device_id,
    350       const em::DevicePolicyRequest& request,
    351       DeviceManagementBackend::DevicePolicyResponseDelegate* delegate)
    352       : DeviceManagementJobBase(
    353           backend_impl,
    354           DeviceManagementBackendImpl::kValueRequestPolicy,
    355           device_id),
    356         delegate_(delegate) {
    357     SetDeviceManagementToken(device_management_token);
    358     em::DeviceManagementRequest request_wrapper;
    359     request_wrapper.mutable_policy_request()->CopyFrom(request);
    360     SetPayload(request_wrapper);
    361   }
    362   virtual ~DeviceManagementPolicyJob() {}
    363 
    364  private:
    365   // DeviceManagementJobBase overrides.
    366   virtual void OnError(DeviceManagementBackend::ErrorCode error) {
    367     delegate_->OnError(error);
    368   }
    369   virtual void OnResponse(const em::DeviceManagementResponse& response) {
    370     delegate_->HandlePolicyResponse(response.policy_response());
    371   }
    372 
    373   DeviceManagementBackend::DevicePolicyResponseDelegate* delegate_;
    374 
    375   DISALLOW_COPY_AND_ASSIGN(DeviceManagementPolicyJob);
    376 };
    377 
    378 DeviceManagementBackendImpl::DeviceManagementBackendImpl(
    379     DeviceManagementService* service)
    380     : service_(service) {
    381 }
    382 
    383 DeviceManagementBackendImpl::~DeviceManagementBackendImpl() {
    384   for (JobSet::iterator job(pending_jobs_.begin());
    385        job != pending_jobs_.end();
    386        ++job) {
    387     service_->RemoveJob(*job);
    388     delete *job;
    389   }
    390   pending_jobs_.clear();
    391 }
    392 
    393 std::string DeviceManagementBackendImpl::GetAgentString() {
    394   static std::string agent;
    395   if (!agent.empty())
    396     return agent;
    397 
    398   chrome::VersionInfo version_info;
    399   agent = base::StringPrintf(kValueAgent,
    400                              version_info.Name().c_str(),
    401                              version_info.Version().c_str(),
    402                              version_info.LastChange().c_str());
    403   return agent;
    404 }
    405 
    406 std::string DeviceManagementBackendImpl::GetPlatformString() {
    407   static std::string platform;
    408   if (!platform.empty())
    409     return platform;
    410 
    411   std::string os_name(base::SysInfo::OperatingSystemName());
    412   std::string os_hardware(base::SysInfo::CPUArchitecture());
    413 
    414 #if defined(OS_CHROMEOS)
    415   chromeos::SystemAccess* sys_lib = chromeos::SystemAccess::GetInstance();
    416 
    417   std::string hwclass;
    418   std::string board;
    419   if (!sys_lib->GetMachineStatistic(kMachineInfoHWClass, &hwclass) ||
    420       !sys_lib->GetMachineStatistic(kMachineInfoBoard, &board)) {
    421     LOG(ERROR) << "Failed to get machine information";
    422   }
    423   os_name += ",CrOS," + board;
    424   os_hardware += "," + hwclass;
    425 #endif
    426 
    427   std::string os_version("-");
    428 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
    429   int32 os_major_version = 0;
    430   int32 os_minor_version = 0;
    431   int32 os_bugfix_version = 0;
    432   base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
    433                                                &os_minor_version,
    434                                                &os_bugfix_version);
    435   os_version = base::StringPrintf("%d.%d.%d",
    436                                   os_major_version,
    437                                   os_minor_version,
    438                                   os_bugfix_version);
    439 #endif
    440 
    441   platform = base::StringPrintf(kValuePlatform,
    442                                 os_name.c_str(),
    443                                 os_hardware.c_str(),
    444                                 os_version.c_str());
    445   return platform;
    446 }
    447 
    448 void DeviceManagementBackendImpl::JobDone(DeviceManagementJobBase* job) {
    449   pending_jobs_.erase(job);
    450 }
    451 
    452 void DeviceManagementBackendImpl::AddJob(DeviceManagementJobBase* job) {
    453   pending_jobs_.insert(job);
    454   service_->AddJob(job);
    455 }
    456 
    457 void DeviceManagementBackendImpl::ProcessRegisterRequest(
    458     const std::string& auth_token,
    459     const std::string& device_id,
    460     const em::DeviceRegisterRequest& request,
    461     DeviceRegisterResponseDelegate* delegate) {
    462   AddJob(new DeviceManagementRegisterJob(this, auth_token, device_id, request,
    463                                          delegate));
    464 }
    465 
    466 void DeviceManagementBackendImpl::ProcessUnregisterRequest(
    467     const std::string& device_management_token,
    468     const std::string& device_id,
    469     const em::DeviceUnregisterRequest& request,
    470     DeviceUnregisterResponseDelegate* delegate) {
    471   AddJob(new DeviceManagementUnregisterJob(this, device_management_token,
    472                                            device_id, request, delegate));
    473 }
    474 
    475 void DeviceManagementBackendImpl::ProcessPolicyRequest(
    476     const std::string& device_management_token,
    477     const std::string& device_id,
    478     const em::DevicePolicyRequest& request,
    479     DevicePolicyResponseDelegate* delegate) {
    480   AddJob(new DeviceManagementPolicyJob(this, device_management_token, device_id,
    481                                        request, delegate));
    482 }
    483 
    484 }  // namespace policy
    485