OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2010 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/stl_util-inl.h" | |
11 #include "base/stringprintf.h" | |
12 #include "chrome/browser/browser_thread.h" | |
13 #include "chrome/common/net/url_request_context_getter.h" | |
14 #include "net/base/cookie_monster.h" | |
15 #include "net/base/escape.h" | |
16 #include "net/base/host_resolver.h" | |
17 #include "net/base/ssl_config_service_defaults.h" | |
18 #include "net/http/http_auth_handler_factory.h" | |
19 #include "net/http/http_network_layer.h" | |
20 #include "net/proxy/proxy_service.h" | |
21 #include "net/url_request/url_request_context.h" | |
22 #include "net/url_request/url_request_status.h" | |
23 #include "chrome/browser/browser_process.h" | |
24 #include "chrome/browser/io_thread.h" | |
25 #include "chrome/browser/net/chrome_net_log.h" | |
26 #include "chrome/common/chrome_version_info.h" | |
27 | |
28 namespace policy { | |
29 | |
30 namespace { | |
31 | |
32 // Name constants for URL query parameters. | |
33 const char kServiceParamRequest[] = "request"; | |
34 const char kServiceParamDeviceType[] = "devicetype"; | |
35 const char kServiceParamDeviceID[] = "deviceid"; | |
36 const char kServiceParamAgent[] = "agent"; | |
37 | |
38 // String constants for the device type and agent we report to the service. | |
39 const char kServiceValueDeviceType[] = "Chrome"; | |
40 const char kServiceValueAgent[] = | |
41 "%s enterprise management client version %s (%s)"; | |
42 | |
43 const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth="; | |
44 const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token="; | |
45 | |
46 } // namespace | |
47 | |
48 // Custom request context implementation that allows to override the user agent, | |
49 // amongst others. Using the default request context is not an option since this | |
50 // service may be constructed before the default request context is created | |
51 // (i.e. before the profile has been loaded). | |
52 class DeviceManagementBackendRequestContext : public URLRequestContext { | |
53 public: | |
54 explicit DeviceManagementBackendRequestContext(IOThread::Globals* io_globals); | |
55 virtual ~DeviceManagementBackendRequestContext(); | |
56 | |
57 private: | |
58 virtual const std::string& GetUserAgent(const GURL& url) const; | |
59 | |
60 std::string user_agent_; | |
61 }; | |
62 | |
63 DeviceManagementBackendRequestContext::DeviceManagementBackendRequestContext( | |
64 IOThread::Globals* io_globals) { | |
65 net_log_ = io_globals->net_log.get(); | |
66 host_resolver_ = io_globals->host_resolver.get(); | |
67 proxy_service_ = net::ProxyService::CreateDirect(); | |
68 ssl_config_service_ = net::SSLConfigService::CreateSystemSSLConfigService(); | |
69 http_auth_handler_factory_ = | |
70 net::HttpAuthHandlerFactory::CreateDefault(host_resolver_); | |
71 http_transaction_factory_ = | |
72 net::HttpNetworkLayer::CreateFactory(host_resolver_, | |
73 io_globals->dnsrr_resolver.get(), | |
74 NULL /* ssl_host_info_factory */, | |
75 proxy_service_, | |
76 ssl_config_service_, | |
77 http_auth_handler_factory_, | |
78 NULL /* network_delegate */, | |
79 net_log_); | |
80 cookie_store_ = new net::CookieMonster(NULL, NULL); | |
81 user_agent_ = DeviceManagementBackendImpl::GetAgentString(); | |
82 accept_language_ = "*"; | |
83 accept_charset_ = "*"; | |
84 } | |
85 | |
86 DeviceManagementBackendRequestContext | |
87 ::~DeviceManagementBackendRequestContext() { | |
88 delete http_transaction_factory_; | |
89 delete http_auth_handler_factory_; | |
90 } | |
91 | |
92 const std::string& | |
93 DeviceManagementBackendRequestContext::GetUserAgent(const GURL& url) const { | |
94 return user_agent_; | |
95 } | |
96 | |
97 // Request context holder. | |
98 class DeviceManagementBackendRequestContextGetter | |
99 : public URLRequestContextGetter { | |
100 public: | |
101 DeviceManagementBackendRequestContextGetter() | |
102 : io_thread_(g_browser_process->io_thread()) {} | |
103 | |
104 // URLRequestContextGetter overrides. | |
105 virtual URLRequestContext* GetURLRequestContext(); | |
106 virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const; | |
107 | |
108 private: | |
109 scoped_refptr<URLRequestContext> context_; | |
110 IOThread* io_thread_; | |
111 }; | |
112 | |
113 | |
114 URLRequestContext* | |
115 DeviceManagementBackendRequestContextGetter::GetURLRequestContext() { | |
eroman
2010/11/08 22:38:56
Could you add an assertion that this is currently
| |
116 if (!context_) | |
117 context_ = new DeviceManagementBackendRequestContext(io_thread_->globals()); | |
118 | |
119 return context_.get(); | |
120 } | |
121 | |
122 scoped_refptr<base::MessageLoopProxy> | |
123 DeviceManagementBackendRequestContextGetter::GetIOMessageLoopProxy() const { | |
124 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); | |
125 } | |
126 | |
127 // Helper class for URL query parameter encoding/decoding. | |
128 class URLQueryParameters { | |
129 public: | |
130 URLQueryParameters() {} | |
131 | |
132 // Add a query parameter. | |
133 void Put(const std::string& name, const std::string& value); | |
134 | |
135 // Produce the query string, taking care of properly encoding and assembling | |
136 // the names and values. | |
137 std::string Encode(); | |
138 | |
139 private: | |
140 typedef std::vector<std::pair<std::string, std::string> > ParameterMap; | |
141 ParameterMap params_; | |
142 | |
143 DISALLOW_COPY_AND_ASSIGN(URLQueryParameters); | |
144 }; | |
145 | |
146 void URLQueryParameters::Put(const std::string& name, | |
147 const std::string& value) { | |
148 params_.push_back(std::make_pair(name, value)); | |
149 } | |
150 | |
151 std::string URLQueryParameters::Encode() { | |
152 std::string result; | |
153 for (ParameterMap::const_iterator entry(params_.begin()); | |
154 entry != params_.end(); | |
155 ++entry) { | |
156 if (entry != params_.begin()) | |
157 result += '&'; | |
158 result += EscapeUrlEncodedData(entry->first); | |
159 result += '='; | |
160 result += EscapeUrlEncodedData(entry->second); | |
161 } | |
162 return result; | |
163 } | |
164 | |
165 // Wraps common response parsing and handling functionality. | |
166 class ResponseHandler { | |
167 public: | |
168 ResponseHandler() {} | |
169 virtual ~ResponseHandler() {} | |
170 | |
171 // Handles the URL request response. | |
172 void HandleResponse(const URLRequestStatus& status, | |
173 int response_code, | |
174 const ResponseCookies& cookies, | |
175 const std::string& data); | |
176 | |
177 // Forwards the given error to the delegate. | |
178 virtual void OnError(DeviceManagementBackend::ErrorCode error) = 0; | |
179 | |
180 private: | |
181 // Implemented by subclasses to handle the decoded response. | |
182 virtual void ProcessResponse( | |
183 const em::DeviceManagementResponse& response) = 0; | |
184 }; | |
185 | |
186 void ResponseHandler::HandleResponse(const URLRequestStatus& status, | |
187 int response_code, | |
188 const ResponseCookies& cookies, | |
189 const std::string& data) { | |
190 if (status.status() != URLRequestStatus::SUCCESS) { | |
191 OnError(DeviceManagementBackend::kErrorRequestFailed); | |
192 return; | |
193 } | |
194 | |
195 if (response_code != 200) { | |
196 OnError(DeviceManagementBackend::kErrorHttpStatus); | |
197 return; | |
198 } | |
199 | |
200 em::DeviceManagementResponse response; | |
201 if (!response.ParseFromString(data)) { | |
202 OnError(DeviceManagementBackend::kErrorResponseDecoding); | |
203 return; | |
204 } | |
205 | |
206 // Check service error code. | |
207 switch (response.error()) { | |
208 case em::DeviceManagementResponse::SUCCESS: | |
209 break; | |
210 case em::DeviceManagementResponse::DEVICE_MANAGEMENT_NOT_SUPPORTED: | |
211 OnError(DeviceManagementBackend::kErrorServiceManagementNotSupported); | |
212 return; | |
213 case em::DeviceManagementResponse::DEVICE_NOT_FOUND: | |
214 OnError(DeviceManagementBackend::kErrorServiceDeviceNotFound); | |
215 return; | |
216 case em::DeviceManagementResponse::DEVICE_MANAGEMENT_TOKEN_INVALID: | |
217 OnError(DeviceManagementBackend::kErrorServiceManagementTokenInvalid); | |
218 return; | |
219 case em::DeviceManagementResponse::ACTIVATION_PENDING: | |
220 OnError(DeviceManagementBackend::kErrorServiceActivationPending); | |
221 return; | |
222 default: | |
223 // This should be caught by the protobuf decoder. | |
224 NOTREACHED(); | |
225 OnError(DeviceManagementBackend::kErrorResponseDecoding); | |
226 return; | |
227 } | |
228 | |
229 ProcessResponse(response); | |
230 } | |
231 | |
232 // Handles device registration responses. | |
233 class RegisterResponseHandler : public ResponseHandler { | |
234 public: | |
235 RegisterResponseHandler( | |
236 DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate) | |
237 : delegate_(delegate) {} | |
238 | |
239 private: | |
240 // ResponseHandler overrides. | |
241 virtual void OnError(DeviceManagementBackend::ErrorCode error) { | |
242 delegate_->OnError(error); | |
243 } | |
244 virtual void ProcessResponse(const em::DeviceManagementResponse& response) { | |
245 delegate_->HandleRegisterResponse(response.register_response()); | |
246 } | |
247 | |
248 DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate_; | |
249 }; | |
250 | |
251 // Handles device unregister responses. | |
252 class UnregisterResponseHandler : public ResponseHandler { | |
253 public: | |
254 UnregisterResponseHandler( | |
255 DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate) | |
256 : delegate_(delegate) {} | |
257 | |
258 private: | |
259 // ResponseHandler overrides. | |
260 virtual void OnError(DeviceManagementBackend::ErrorCode error) { | |
261 delegate_->OnError(error); | |
262 } | |
263 virtual void ProcessResponse(const em::DeviceManagementResponse& response) { | |
264 delegate_->HandleUnregisterResponse(response.unregister_response()); | |
265 } | |
266 | |
267 DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate_; | |
268 }; | |
269 | |
270 // Handles device policy responses. | |
271 class PolicyResponseHandler : public ResponseHandler { | |
272 public: | |
273 PolicyResponseHandler( | |
274 DeviceManagementBackend::DevicePolicyResponseDelegate* delegate) | |
275 : delegate_(delegate) {} | |
276 | |
277 private: | |
278 // ResponseHandler overrides. | |
279 virtual void OnError(DeviceManagementBackend::ErrorCode error) { | |
280 delegate_->OnError(error); | |
281 } | |
282 virtual void ProcessResponse(const em::DeviceManagementResponse& response) { | |
283 delegate_->HandlePolicyResponse(response.policy_response()); | |
284 } | |
285 | |
286 DeviceManagementBackend::DevicePolicyResponseDelegate* delegate_; | |
287 }; | |
288 | |
289 DeviceManagementBackendImpl::DeviceManagementBackendImpl( | |
290 const std::string& server_url) | |
291 : server_url_(server_url), | |
292 request_context_getter_( | |
293 new DeviceManagementBackendRequestContextGetter()) { | |
294 } | |
295 | |
296 DeviceManagementBackendImpl::~DeviceManagementBackendImpl() { | |
297 // Cancel all pending requests. | |
298 STLDeleteContainerPairPointers(response_handlers_.begin(), | |
299 response_handlers_.end()); | |
300 } | |
301 | |
302 void DeviceManagementBackendImpl::ProcessRegisterRequest( | |
303 const std::string& auth_token, | |
304 const std::string& device_id, | |
305 const em::DeviceRegisterRequest& request, | |
306 DeviceRegisterResponseDelegate* delegate) { | |
307 em::DeviceManagementRequest request_wrapper; | |
308 request_wrapper.mutable_register_request()->CopyFrom(request); | |
309 | |
310 URLQueryParameters params; | |
311 PutCommonQueryParameters(¶ms); | |
312 params.Put(kServiceParamRequest, "register"); | |
313 params.Put(kServiceParamDeviceID, device_id); | |
314 | |
315 CreateFetcher(request_wrapper, | |
316 new RegisterResponseHandler(delegate), | |
317 params.Encode(), | |
318 kServiceTokenAuthHeader + auth_token); | |
319 } | |
320 | |
321 void DeviceManagementBackendImpl::ProcessUnregisterRequest( | |
322 const std::string& device_management_token, | |
323 const em::DeviceUnregisterRequest& request, | |
324 DeviceUnregisterResponseDelegate* delegate) { | |
325 em::DeviceManagementRequest request_wrapper; | |
326 request_wrapper.mutable_unregister_request()->CopyFrom(request); | |
327 | |
328 URLQueryParameters params; | |
329 PutCommonQueryParameters(¶ms); | |
330 params.Put(kServiceParamRequest, "unregister"); | |
331 | |
332 CreateFetcher(request_wrapper, | |
333 new UnregisterResponseHandler(delegate), | |
334 params.Encode(), | |
335 kDMTokenAuthHeader + device_management_token); | |
336 } | |
337 | |
338 void DeviceManagementBackendImpl::ProcessPolicyRequest( | |
339 const std::string& device_management_token, | |
340 const em::DevicePolicyRequest& request, | |
341 DevicePolicyResponseDelegate* delegate) { | |
342 em::DeviceManagementRequest request_wrapper; | |
343 request_wrapper.mutable_policy_request()->CopyFrom(request); | |
344 | |
345 URLQueryParameters params; | |
346 PutCommonQueryParameters(¶ms); | |
347 params.Put(kServiceParamRequest, "policy"); | |
348 | |
349 CreateFetcher(request_wrapper, | |
350 new PolicyResponseHandler(delegate), | |
351 params.Encode(), | |
352 kDMTokenAuthHeader + device_management_token); | |
353 } | |
354 | |
355 // static | |
356 std::string DeviceManagementBackendImpl::GetAgentString() { | |
357 chrome::VersionInfo version_info; | |
358 return base::StringPrintf(kServiceValueAgent, | |
359 version_info.Name().c_str(), | |
360 version_info.Version().c_str(), | |
361 version_info.LastChange().c_str()); | |
362 } | |
363 | |
364 void DeviceManagementBackendImpl::OnURLFetchComplete( | |
365 const URLFetcher* source, | |
366 const GURL& url, | |
367 const URLRequestStatus& status, | |
368 int response_code, | |
369 const ResponseCookies& cookies, | |
370 const std::string& data) { | |
371 ResponseHandlerMap::iterator entry(response_handlers_.find(source)); | |
372 if (entry != response_handlers_.end()) { | |
373 ResponseHandler* handler = entry->second; | |
374 handler->HandleResponse(status, response_code, cookies, data); | |
375 response_handlers_.erase(entry); | |
376 delete handler; | |
377 } else { | |
378 NOTREACHED() << "Callback from foreign URL fetcher"; | |
379 } | |
380 delete source; | |
381 } | |
382 | |
383 void DeviceManagementBackendImpl::CreateFetcher( | |
384 const em::DeviceManagementRequest& request, | |
385 ResponseHandler* handler, | |
386 const std::string& query_params, | |
387 const std::string& extra_headers) { | |
388 scoped_ptr<ResponseHandler> handler_ptr(handler); | |
389 | |
390 // Construct the payload. | |
391 std::string payload; | |
392 if (!request.SerializeToString(&payload)) { | |
393 handler->OnError(DeviceManagementBackend::kErrorRequestInvalid); | |
394 return; | |
395 } | |
396 | |
397 // Instantiate the fetcher. | |
398 GURL url(server_url_ + '?' + query_params); | |
399 URLFetcher* fetcher = URLFetcher::Create(0, url, URLFetcher::POST, this); | |
400 fetcher->set_request_context(request_context_getter_.get()); | |
401 fetcher->set_upload_data("application/octet-stream", payload); | |
402 fetcher->set_extra_request_headers(extra_headers); | |
403 response_handlers_[fetcher] = handler_ptr.release(); | |
404 | |
405 // Start the request. The fetcher will call OnURLFetchComplete when done. | |
406 fetcher->Start(); | |
407 } | |
408 | |
409 void DeviceManagementBackendImpl::PutCommonQueryParameters( | |
410 URLQueryParameters* params) { | |
411 params->Put(kServiceParamDeviceType, kServiceValueDeviceType); | |
412 params->Put(kServiceParamAgent, GetAgentString()); | |
413 } | |
414 | |
415 } // namespace policy | |
OLD | NEW |