OLD | NEW |
---|---|
1 #!/usr/bin/python2.5 | 1 #!/usr/bin/python2.5 |
2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """A bare-bones test server for testing cloud policy support. | 6 """A bare-bones test server for testing cloud policy support. |
7 | 7 |
8 This implements a simple cloud policy test server that can be used to test | 8 This implements a simple cloud policy test server that can be used to test |
9 chrome's device management service client. The policy information is read from | 9 chrome's device management service client. The policy information is read from |
10 from files in a directory. The files should contain policy definitions in JSON | 10 from files in a directory. The files should contain policy definitions in JSON |
11 format, using the top-level dictionary as a key/value store. The format is | 11 format, using the top-level dictionary as a key/value store. The format is |
12 identical to what the Linux implementation reads from /etc. Here is an example: | 12 identical to what the Linux implementation reads from /etc. Here is an example: |
13 | 13 |
14 { | 14 { |
15 "HomepageLocation" : "http://www.chromium.org" | 15 "HomepageLocation" : "http://www.chromium.org" |
16 } | 16 } |
17 | 17 |
18 """ | 18 """ |
19 | 19 |
20 import calendar | |
20 import cgi | 21 import cgi |
21 import logging | 22 import logging |
22 import random | 23 import random |
23 import re | 24 import re |
24 import sys | 25 import sys |
26 import time | |
25 | 27 |
26 # The name and availability of the json module varies in python versions. | 28 # The name and availability of the json module varies in python versions. |
27 try: | 29 try: |
28 import simplejson as json | 30 import simplejson as json |
29 except ImportError: | 31 except ImportError: |
30 try: | 32 try: |
31 import json | 33 import json |
32 except ImportError: | 34 except ImportError: |
33 json = None | 35 json = None |
34 | 36 |
35 import device_management_backend_pb2 as dm | 37 import device_management_backend_pb2 as dm |
38 import cloud_policy_pb2 as cp | |
39 | |
40 LOG_FILENAME = '/dev/stdout' | |
41 logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG) | |
Mattias Nissler (ping if slow)
2011/01/25 11:05:57
I guess these two lines are not meant for committi
| |
36 | 42 |
37 class RequestHandler(object): | 43 class RequestHandler(object): |
38 """Decodes and handles device management requests from clients. | 44 """Decodes and handles device management requests from clients. |
39 | 45 |
40 The handler implements all the request parsing and protobuf message decoding | 46 The handler implements all the request parsing and protobuf message decoding |
41 and encoding. It calls back into the server to lookup, register, and | 47 and encoding. It calls back into the server to lookup, register, and |
42 unregister clients. | 48 unregister clients. |
43 """ | 49 """ |
44 | 50 |
45 def __init__(self, server, path, headers, request): | 51 def __init__(self, server, path, headers, request): |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
88 | 94 |
89 self.DumpMessage('Request', rmsg) | 95 self.DumpMessage('Request', rmsg) |
90 | 96 |
91 request_type = self.GetUniqueParam('request') | 97 request_type = self.GetUniqueParam('request') |
92 if request_type == 'register': | 98 if request_type == 'register': |
93 return self.ProcessRegister(rmsg.register_request) | 99 return self.ProcessRegister(rmsg.register_request) |
94 elif request_type == 'unregister': | 100 elif request_type == 'unregister': |
95 return self.ProcessUnregister(rmsg.unregister_request) | 101 return self.ProcessUnregister(rmsg.unregister_request) |
96 elif request_type == 'policy': | 102 elif request_type == 'policy': |
97 return self.ProcessPolicy(rmsg.policy_request) | 103 return self.ProcessPolicy(rmsg.policy_request) |
104 elif request_type == 'cloud_policy': | |
105 return self.ProcessCloudPolicyRequest(rmsg.cloud_policy_request) | |
98 else: | 106 else: |
99 return (400, 'Invalid request parameter') | 107 return (400, 'Invalid request parameter') |
100 | 108 |
101 def ProcessRegister(self, msg): | 109 def ProcessRegister(self, msg): |
102 """Handles a register request. | 110 """Handles a register request. |
103 | 111 |
104 Checks the query for authorization and device identifier, registers the | 112 Checks the query for authorization and device identifier, registers the |
105 device with the server and constructs a response. | 113 device with the server and constructs a response. |
106 | 114 |
107 Args: | 115 Args: |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
207 entry_value.value_type = dm.GenericValue.VALUE_TYPE_STRING_ARRAY | 215 entry_value.value_type = dm.GenericValue.VALUE_TYPE_STRING_ARRAY |
208 for list_entry in value: | 216 for list_entry in value: |
209 entry_value.string_array.append(str(list_entry)) | 217 entry_value.string_array.append(str(list_entry)) |
210 entry.value.CopyFrom(entry_value) | 218 entry.value.CopyFrom(entry_value) |
211 setting.policy_value.CopyFrom(policy_value) | 219 setting.policy_value.CopyFrom(policy_value) |
212 | 220 |
213 self.DumpMessage('Response', response) | 221 self.DumpMessage('Response', response) |
214 | 222 |
215 return (200, response.SerializeToString()) | 223 return (200, response.SerializeToString()) |
216 | 224 |
225 def _SetProtobufMessageField(self, group_message, field, field_value): | |
226 '''Sets a field in a protobuf message. | |
227 | |
228 Args: | |
229 group_message: The protobuf message. | |
230 field: The field of the message to set, it shuold be a member of | |
231 group_message.DESCRIPTOR.fields. | |
232 field_value: The value to set. | |
233 ''' | |
234 if field.type == field.TYPE_BYTES: | |
235 assert type(field_value) == list | |
236 string_list = cp.StringList() | |
237 for list_item in field_value: | |
238 string_list.entry.append(list_item) | |
239 serialized_string_list = string_list.SerializeToString() | |
240 group_message.__setattr__(field.name, serialized_string_list) | |
241 else: | |
242 # Simple cases: | |
243 if field.type == field.TYPE_BOOL: | |
244 assert type(field_value) == bool | |
245 elif field.type == field.TYPE_STRING: | |
246 assert type(field_value) == str | |
247 elif field.type == field.TYPE_INT64: | |
248 assert type(field_value) == int | |
249 else: | |
250 raise Exception('Unknown field type %s' % field.type_name) | |
251 group_message.__setattr__(field.name, field_value) | |
252 | |
253 def ProcessCloudPolicyRequest(self, msg): | |
254 token, response = self.CheckToken() | |
255 if not token: | |
256 return response | |
257 | |
258 settings = cp.CloudPolicySettings() | |
259 | |
260 if msg.policy_scope == 'chromeos/device': | |
261 pass | |
262 | |
263 for group in settings.DESCRIPTOR.fields: | |
264 # Create protobuf message for group. | |
265 group_message = eval('cp.' + group.message_type.name + '()') | |
266 # Indiactes if at least one field was set in |group_message|. | |
267 got_fields = False | |
268 # Iterate over fields of the message and feed them from the | |
269 # policy config file. | |
270 for field in group_message.DESCRIPTOR.fields: | |
271 if field.name in self._server.policy: | |
272 got_fields = True | |
273 field_value = self._server.policy[field.name] | |
274 self._SetProtobufMessageField(group_message, field, field_value) | |
275 if got_fields: | |
276 settings.__getattribute__(group.name).CopyFrom(group_message) | |
277 | |
278 # Construct response | |
279 signed_response = dm.SignedCloudPolicyResponse() | |
280 signed_response.settings.CopyFrom(settings) | |
281 signed_response.timestamp = calendar.timegm(time.gmtime()) | |
282 signed_response.device_token = token; | |
283 signed_response.device_name = 'TODO'; | |
284 | |
285 cloud_response = dm.CloudPolicyResponse() | |
286 cloud_response.signed_response = signed_response.SerializeToString() | |
287 cloud_response.signature = 'TODO' | |
Mattias Nissler (ping if slow)
2011/01/25 11:05:57
should have some actual signing here :) Maybe pass
| |
288 | |
289 response = dm.DeviceManagementResponse() | |
290 response.error = dm.DeviceManagementResponse.SUCCESS | |
291 response.cloud_policy_response.CopyFrom(cloud_response) | |
292 | |
293 self.DumpMessage('Response', response) | |
294 | |
295 return (200, response.SerializeToString()) | |
296 | |
217 def CheckToken(self): | 297 def CheckToken(self): |
218 """Helper for checking whether the client supplied a valid DM token. | 298 """Helper for checking whether the client supplied a valid DM token. |
219 | 299 |
220 Extracts the token from the request and passed to the server in order to | 300 Extracts the token from the request and passed to the server in order to |
221 look up the client. Returns a pair of token and error response. If the token | 301 look up the client. Returns a pair of token and error response. If the token |
222 is None, the error response is a pair of status code and error message. | 302 is None, the error response is a pair of status code and error message. |
223 | 303 |
224 Returns: | 304 Returns: |
225 A pair of DM token and error response. If the token is None, the message | 305 A pair of DM token and error response. If the token is None, the message |
226 will contain the error response to send back. | 306 will contain the error response to send back. |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
311 return self._registered_devices.get(dmtoken, None) | 391 return self._registered_devices.get(dmtoken, None) |
312 | 392 |
313 def UnregisterDevice(self, dmtoken): | 393 def UnregisterDevice(self, dmtoken): |
314 """Unregisters a device identified by the given DM token. | 394 """Unregisters a device identified by the given DM token. |
315 | 395 |
316 Args: | 396 Args: |
317 dmtoken: The device management token provided by the client. | 397 dmtoken: The device management token provided by the client. |
318 """ | 398 """ |
319 if dmtoken in self._registered_devices: | 399 if dmtoken in self._registered_devices: |
320 del self._registered_devices[dmtoken] | 400 del self._registered_devices[dmtoken] |
OLD | NEW |