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