Chromium Code Reviews| 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 |