device_management_backend_impl.cc revision dc0f95d653279beabeb9817299e2902918ba123e
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#include "base/stringprintf.h" 11#include "net/base/escape.h" 12#include "net/url_request/url_request_status.h" 13#include "chrome/browser/policy/device_management_service.h" 14#include "chrome/common/chrome_version_info.h" 15 16namespace policy { 17 18// Name constants for URL query parameters. 19const char DeviceManagementBackendImpl::kParamRequest[] = "request"; 20const char DeviceManagementBackendImpl::kParamDeviceType[] = "devicetype"; 21const char DeviceManagementBackendImpl::kParamAppType[] = "apptype"; 22const char DeviceManagementBackendImpl::kParamDeviceID[] = "deviceid"; 23const char DeviceManagementBackendImpl::kParamAgent[] = "agent"; 24 25// String constants for the device and app type we report to the server. 26const char DeviceManagementBackendImpl::kValueRequestRegister[] = "register"; 27const char DeviceManagementBackendImpl::kValueRequestUnregister[] = 28 "unregister"; 29const char DeviceManagementBackendImpl::kValueRequestPolicy[] = "policy"; 30const char DeviceManagementBackendImpl::kValueDeviceType[] = "2"; 31const char DeviceManagementBackendImpl::kValueAppType[] = "Chrome"; 32 33namespace { 34 35const char kValueAgent[] = "%s enterprise management client %s (%s)"; 36 37const char kPostContentType[] = "application/protobuf"; 38 39const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth="; 40const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token="; 41 42} // namespace 43 44// Helper class for URL query parameter encoding/decoding. 45class URLQueryParameters { 46 public: 47 URLQueryParameters() {} 48 49 // Add a query parameter. 50 void Put(const std::string& name, const std::string& value); 51 52 // Produce the query string, taking care of properly encoding and assembling 53 // the names and values. 54 std::string Encode(); 55 56 private: 57 typedef std::vector<std::pair<std::string, std::string> > ParameterMap; 58 ParameterMap params_; 59 60 DISALLOW_COPY_AND_ASSIGN(URLQueryParameters); 61}; 62 63void URLQueryParameters::Put(const std::string& name, 64 const std::string& value) { 65 params_.push_back(std::make_pair(name, value)); 66} 67 68std::string URLQueryParameters::Encode() { 69 std::string result; 70 for (ParameterMap::const_iterator entry(params_.begin()); 71 entry != params_.end(); 72 ++entry) { 73 if (entry != params_.begin()) 74 result += '&'; 75 result += EscapeUrlEncodedData(entry->first); 76 result += '='; 77 result += EscapeUrlEncodedData(entry->second); 78 } 79 return result; 80} 81 82// A base class containing the common code for the jobs created by the backend 83// implementation. Subclasses provide custom code for handling actual register, 84// unregister, and policy jobs. 85class DeviceManagementJobBase 86 : public DeviceManagementService::DeviceManagementJob { 87 public: 88 virtual ~DeviceManagementJobBase() { 89 backend_impl_->JobDone(this); 90 } 91 92 // DeviceManagementJob overrides: 93 virtual void HandleResponse(const net::URLRequestStatus& status, 94 int response_code, 95 const ResponseCookies& cookies, 96 const std::string& data); 97 virtual GURL GetURL(const std::string& server_url); 98 virtual void ConfigureRequest(URLFetcher* fetcher); 99 100 protected: 101 // Constructs a device management job running for the given backend. 102 DeviceManagementJobBase(DeviceManagementBackendImpl* backend_impl, 103 const std::string& request_type, 104 const std::string& device_id) 105 : backend_impl_(backend_impl) { 106 query_params_.Put(DeviceManagementBackendImpl::kParamRequest, request_type); 107 query_params_.Put(DeviceManagementBackendImpl::kParamDeviceType, 108 DeviceManagementBackendImpl::kValueDeviceType); 109 query_params_.Put(DeviceManagementBackendImpl::kParamAppType, 110 DeviceManagementBackendImpl::kValueAppType); 111 query_params_.Put(DeviceManagementBackendImpl::kParamDeviceID, device_id); 112 query_params_.Put(DeviceManagementBackendImpl::kParamAgent, 113 DeviceManagementBackendImpl::GetAgentString()); 114 } 115 116 void SetQueryParam(const std::string& name, const std::string& value) { 117 query_params_.Put(name, value); 118 } 119 120 void SetAuthToken(const std::string& auth_token) { 121 auth_token_ = auth_token; 122 } 123 124 void SetDeviceManagementToken(const std::string& device_management_token) { 125 device_management_token_ = device_management_token; 126 } 127 128 void SetPayload(const em::DeviceManagementRequest& request) { 129 if (!request.SerializeToString(&payload_)) { 130 NOTREACHED(); 131 LOG(ERROR) << "Failed to serialize request."; 132 } 133 } 134 135 private: 136 // Implemented by subclasses to handle decoded responses and errors. 137 virtual void OnResponse( 138 const em::DeviceManagementResponse& response) = 0; 139 virtual void OnError(DeviceManagementBackend::ErrorCode error) = 0; 140 141 // The backend this job is handling a request for. 142 DeviceManagementBackendImpl* backend_impl_; 143 144 // Query parameters. 145 URLQueryParameters query_params_; 146 147 // Auth token (if applicaple). 148 std::string auth_token_; 149 150 // Device management token (if applicable). 151 std::string device_management_token_; 152 153 // The payload. 154 std::string payload_; 155 156 DISALLOW_COPY_AND_ASSIGN(DeviceManagementJobBase); 157}; 158 159void DeviceManagementJobBase::HandleResponse( 160 const net::URLRequestStatus& status, 161 int response_code, 162 const ResponseCookies& cookies, 163 const std::string& data) { 164 // Delete ourselves when this is done. 165 scoped_ptr<DeviceManagementJob> scoped_killer(this); 166 167 if (status.status() != net::URLRequestStatus::SUCCESS) { 168 OnError(DeviceManagementBackend::kErrorRequestFailed); 169 return; 170 } 171 172 if (response_code != 200) { 173 if (response_code == 400) 174 OnError(DeviceManagementBackend::kErrorRequestInvalid); 175 else 176 OnError(DeviceManagementBackend::kErrorHttpStatus); 177 return; 178 } 179 180 em::DeviceManagementResponse response; 181 if (!response.ParseFromString(data)) { 182 OnError(DeviceManagementBackend::kErrorResponseDecoding); 183 return; 184 } 185 186 // Check service error code. 187 switch (response.error()) { 188 case em::DeviceManagementResponse::SUCCESS: 189 OnResponse(response); 190 return; 191 case em::DeviceManagementResponse::DEVICE_MANAGEMENT_NOT_SUPPORTED: 192 OnError(DeviceManagementBackend::kErrorServiceManagementNotSupported); 193 return; 194 case em::DeviceManagementResponse::DEVICE_NOT_FOUND: 195 OnError(DeviceManagementBackend::kErrorServiceDeviceNotFound); 196 return; 197 case em::DeviceManagementResponse::DEVICE_MANAGEMENT_TOKEN_INVALID: 198 OnError(DeviceManagementBackend::kErrorServiceManagementTokenInvalid); 199 return; 200 case em::DeviceManagementResponse::ACTIVATION_PENDING: 201 OnError(DeviceManagementBackend::kErrorServiceActivationPending); 202 return; 203 case em::DeviceManagementResponse::POLICY_NOT_FOUND: 204 OnError(DeviceManagementBackend::kErrorServicePolicyNotFound); 205 return; 206 } 207 208 // This should be caught by the protobuf decoder. 209 NOTREACHED(); 210 OnError(DeviceManagementBackend::kErrorResponseDecoding); 211} 212 213GURL DeviceManagementJobBase::GetURL( 214 const std::string& server_url) { 215 return GURL(server_url + '?' + query_params_.Encode()); 216} 217 218void DeviceManagementJobBase::ConfigureRequest(URLFetcher* fetcher) { 219 fetcher->set_upload_data(kPostContentType, payload_); 220 std::string extra_headers; 221 if (!auth_token_.empty()) 222 extra_headers += kServiceTokenAuthHeader + auth_token_ + "\n"; 223 if (!device_management_token_.empty()) 224 extra_headers += kDMTokenAuthHeader + device_management_token_ + "\n"; 225 fetcher->set_extra_request_headers(extra_headers); 226} 227 228// Handles device registration jobs. 229class DeviceManagementRegisterJob : public DeviceManagementJobBase { 230 public: 231 DeviceManagementRegisterJob( 232 DeviceManagementBackendImpl* backend_impl, 233 const std::string& auth_token, 234 const std::string& device_id, 235 const em::DeviceRegisterRequest& request, 236 DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate) 237 : DeviceManagementJobBase( 238 backend_impl, 239 DeviceManagementBackendImpl::kValueRequestRegister, 240 device_id), 241 delegate_(delegate) { 242 SetAuthToken(auth_token); 243 em::DeviceManagementRequest request_wrapper; 244 request_wrapper.mutable_register_request()->CopyFrom(request); 245 SetPayload(request_wrapper); 246 } 247 virtual ~DeviceManagementRegisterJob() {} 248 249 private: 250 // DeviceManagementJobBase overrides. 251 virtual void OnError(DeviceManagementBackend::ErrorCode error) { 252 delegate_->OnError(error); 253 } 254 virtual void OnResponse(const em::DeviceManagementResponse& response) { 255 delegate_->HandleRegisterResponse(response.register_response()); 256 } 257 258 DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate_; 259 260 DISALLOW_COPY_AND_ASSIGN(DeviceManagementRegisterJob); 261}; 262 263// Handles device unregistration jobs. 264class DeviceManagementUnregisterJob : public DeviceManagementJobBase { 265 public: 266 DeviceManagementUnregisterJob( 267 DeviceManagementBackendImpl* backend_impl, 268 const std::string& device_management_token, 269 const std::string& device_id, 270 const em::DeviceUnregisterRequest& request, 271 DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate) 272 : DeviceManagementJobBase( 273 backend_impl, 274 DeviceManagementBackendImpl::kValueRequestUnregister, 275 device_id), 276 delegate_(delegate) { 277 SetDeviceManagementToken(device_management_token); 278 em::DeviceManagementRequest request_wrapper; 279 request_wrapper.mutable_unregister_request()->CopyFrom(request); 280 SetPayload(request_wrapper); 281 } 282 virtual ~DeviceManagementUnregisterJob() {} 283 284 private: 285 // DeviceManagementJobBase overrides. 286 virtual void OnError(DeviceManagementBackend::ErrorCode error) { 287 delegate_->OnError(error); 288 } 289 virtual void OnResponse(const em::DeviceManagementResponse& response) { 290 delegate_->HandleUnregisterResponse(response.unregister_response()); 291 } 292 293 DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate_; 294 295 DISALLOW_COPY_AND_ASSIGN(DeviceManagementUnregisterJob); 296}; 297 298// Handles policy request jobs. 299class DeviceManagementPolicyJob : public DeviceManagementJobBase { 300 public: 301 DeviceManagementPolicyJob( 302 DeviceManagementBackendImpl* backend_impl, 303 const std::string& device_management_token, 304 const std::string& device_id, 305 const em::DevicePolicyRequest& request, 306 DeviceManagementBackend::DevicePolicyResponseDelegate* delegate) 307 : DeviceManagementJobBase( 308 backend_impl, 309 DeviceManagementBackendImpl::kValueRequestPolicy, 310 device_id), 311 delegate_(delegate) { 312 SetDeviceManagementToken(device_management_token); 313 em::DeviceManagementRequest request_wrapper; 314 request_wrapper.mutable_policy_request()->CopyFrom(request); 315 SetPayload(request_wrapper); 316 } 317 virtual ~DeviceManagementPolicyJob() {} 318 319 private: 320 // DeviceManagementJobBase overrides. 321 virtual void OnError(DeviceManagementBackend::ErrorCode error) { 322 delegate_->OnError(error); 323 } 324 virtual void OnResponse(const em::DeviceManagementResponse& response) { 325 delegate_->HandlePolicyResponse(response.policy_response()); 326 } 327 328 DeviceManagementBackend::DevicePolicyResponseDelegate* delegate_; 329 330 DISALLOW_COPY_AND_ASSIGN(DeviceManagementPolicyJob); 331}; 332 333DeviceManagementBackendImpl::DeviceManagementBackendImpl( 334 DeviceManagementService* service) 335 : service_(service) { 336} 337 338DeviceManagementBackendImpl::~DeviceManagementBackendImpl() { 339 // Swap to a helper, so we don't interfere with the unregistration on delete. 340 JobSet to_be_deleted; 341 to_be_deleted.swap(pending_jobs_); 342 for (JobSet::iterator job(to_be_deleted.begin()); 343 job != to_be_deleted.end(); 344 ++job) { 345 service_->RemoveJob(*job); 346 delete *job; 347 } 348} 349 350std::string DeviceManagementBackendImpl::GetAgentString() { 351 chrome::VersionInfo version_info; 352 return base::StringPrintf(kValueAgent, 353 version_info.Name().c_str(), 354 version_info.Version().c_str(), 355 version_info.LastChange().c_str()); 356} 357 358void DeviceManagementBackendImpl::JobDone(DeviceManagementJobBase* job) { 359 pending_jobs_.erase(job); 360} 361 362void DeviceManagementBackendImpl::AddJob(DeviceManagementJobBase* job) { 363 pending_jobs_.insert(job); 364 service_->AddJob(job); 365} 366 367void DeviceManagementBackendImpl::ProcessRegisterRequest( 368 const std::string& auth_token, 369 const std::string& device_id, 370 const em::DeviceRegisterRequest& request, 371 DeviceRegisterResponseDelegate* delegate) { 372 AddJob(new DeviceManagementRegisterJob(this, auth_token, device_id, request, 373 delegate)); 374} 375 376void DeviceManagementBackendImpl::ProcessUnregisterRequest( 377 const std::string& device_management_token, 378 const std::string& device_id, 379 const em::DeviceUnregisterRequest& request, 380 DeviceUnregisterResponseDelegate* delegate) { 381 AddJob(new DeviceManagementUnregisterJob(this, device_management_token, 382 device_id, request, delegate)); 383} 384 385void DeviceManagementBackendImpl::ProcessPolicyRequest( 386 const std::string& device_management_token, 387 const std::string& device_id, 388 const em::DevicePolicyRequest& request, 389 DevicePolicyResponseDelegate* delegate) { 390 AddJob(new DeviceManagementPolicyJob(this, device_management_token, device_id, 391 request, delegate)); 392} 393 394} // namespace policy 395