OLD | NEW |
---|---|
1 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """A bare-bones test server for testing cloud policy support. | 5 """A bare-bones test server for testing cloud policy support. |
6 | 6 |
7 This implements a simple cloud policy test server that can be used to test | 7 This implements a simple cloud policy test server that can be used to test |
8 chrome's device management service client. The policy information is read from | 8 chrome's device management service client. The policy information is read from |
9 the file named device_management in the server's data directory. It contains | 9 the file named device_management in the server's data directory. It contains |
10 enforced and recommended policies for the device and user scope, and a list | 10 enforced and recommended policies for the device and user scope, and a list |
(...skipping 26 matching lines...) Expand all Loading... | |
37 } | 37 } |
38 }, | 38 }, |
39 "managed_users" : [ | 39 "managed_users" : [ |
40 "secret123456" | 40 "secret123456" |
41 ] | 41 ] |
42 } | 42 } |
43 | 43 |
44 """ | 44 """ |
45 | 45 |
46 import cgi | 46 import cgi |
47 import hashlib | |
47 import logging | 48 import logging |
48 import os | 49 import os |
49 import random | 50 import random |
50 import re | 51 import re |
51 import sys | 52 import sys |
52 import time | 53 import time |
53 import tlslite | 54 import tlslite |
54 import tlslite.api | 55 import tlslite.api |
55 import tlslite.utils | 56 import tlslite.utils |
56 | 57 |
57 # The name and availability of the json module varies in python versions. | 58 # The name and availability of the json module varies in python versions. |
58 try: | 59 try: |
59 import simplejson as json | 60 import simplejson as json |
60 except ImportError: | 61 except ImportError: |
61 try: | 62 try: |
62 import json | 63 import json |
63 except ImportError: | 64 except ImportError: |
64 json = None | 65 json = None |
65 | 66 |
66 import asn1der | 67 import asn1der |
67 import device_management_backend_pb2 as dm | 68 import device_management_backend_pb2 as dm |
68 import cloud_policy_pb2 as cp | 69 import cloud_policy_pb2 as cp |
69 import chrome_device_policy_pb2 as dp | 70 import chrome_device_policy_pb2 as dp |
70 | 71 |
71 # ASN.1 object identifier for PKCS#1/RSA. | 72 # ASN.1 object identifier for PKCS#1/RSA. |
72 PKCS1_RSA_OID = '\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01' | 73 PKCS1_RSA_OID = '\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01' |
73 | 74 |
75 # SHA256 sum of "0". | |
76 SHA256_0 = hashlib.sha256('0').digest() | |
pastarmovj
2011/12/01 09:30:04
If you only use haslib for this call why don't you
Joao da Silva
2011/12/01 09:42:07
I prefer this format since it's less magical, and
pastarmovj
2011/12/01 09:49:03
Ok I am fine with that.
| |
77 | |
74 class RequestHandler(object): | 78 class RequestHandler(object): |
75 """Decodes and handles device management requests from clients. | 79 """Decodes and handles device management requests from clients. |
76 | 80 |
77 The handler implements all the request parsing and protobuf message decoding | 81 The handler implements all the request parsing and protobuf message decoding |
78 and encoding. It calls back into the server to lookup, register, and | 82 and encoding. It calls back into the server to lookup, register, and |
79 unregister clients. | 83 unregister clients. |
80 """ | 84 """ |
81 | 85 |
82 def __init__(self, server, path, headers, request): | 86 def __init__(self, server, path, headers, request): |
83 """Initialize the handler. | 87 """Initialize the handler. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
137 (request_type != 'ping' and | 141 (request_type != 'ping' and |
138 len(self.GetUniqueParam('deviceid')) >= 64) or | 142 len(self.GetUniqueParam('deviceid')) >= 64) or |
139 len(self.GetUniqueParam('agent')) >= 64): | 143 len(self.GetUniqueParam('agent')) >= 64): |
140 return (400, 'Invalid request parameter') | 144 return (400, 'Invalid request parameter') |
141 if request_type == 'register': | 145 if request_type == 'register': |
142 return self.ProcessRegister(rmsg.register_request) | 146 return self.ProcessRegister(rmsg.register_request) |
143 elif request_type == 'unregister': | 147 elif request_type == 'unregister': |
144 return self.ProcessUnregister(rmsg.unregister_request) | 148 return self.ProcessUnregister(rmsg.unregister_request) |
145 elif request_type == 'policy' or request_type == 'ping': | 149 elif request_type == 'policy' or request_type == 'ping': |
146 return self.ProcessPolicy(rmsg.policy_request, request_type) | 150 return self.ProcessPolicy(rmsg.policy_request, request_type) |
151 elif request_type == 'enterprise_check': | |
152 return self.ProcessAutoEnrollment(rmsg.auto_enrollment_request) | |
147 else: | 153 else: |
148 return (400, 'Invalid request parameter') | 154 return (400, 'Invalid request parameter') |
149 | 155 |
150 def CheckGoogleLogin(self): | 156 def CheckGoogleLogin(self): |
151 """Extracts the auth token from the request and returns it. The token may | 157 """Extracts the auth token from the request and returns it. The token may |
152 either be a GoogleLogin token from an Authorization header, or an OAuth V2 | 158 either be a GoogleLogin token from an Authorization header, or an OAuth V2 |
153 token from the oauth_token query parameter. Returns None if no token is | 159 token from the oauth_token query parameter. Returns None if no token is |
154 present. | 160 present. |
155 """ | 161 """ |
156 oauth_token = self.GetUniqueParam('oauth_token') | 162 oauth_token = self.GetUniqueParam('oauth_token') |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
247 for request in msg.request: | 253 for request in msg.request: |
248 if (request.policy_type in | 254 if (request.policy_type in |
249 ('google/chromeos/user', 'google/chromeos/device')): | 255 ('google/chromeos/user', 'google/chromeos/device')): |
250 if request_type != 'policy': | 256 if request_type != 'policy': |
251 return (400, 'Invalid request type') | 257 return (400, 'Invalid request type') |
252 else: | 258 else: |
253 return self.ProcessCloudPolicy(request) | 259 return self.ProcessCloudPolicy(request) |
254 else: | 260 else: |
255 return (400, 'Invalid policy_type') | 261 return (400, 'Invalid policy_type') |
256 | 262 |
263 def ProcessAutoEnrollment(self, msg): | |
264 """Handles an auto-enrollment check request. | |
265 | |
266 The reply depends on the value of the modulus: | |
267 1: replies with no new modulus and the sha256 hash of "0" | |
268 2: replies with a new modulus, 4. | |
269 4: replies with a new modulus, 2. | |
270 8: fails with error 400. | |
271 anything else: replies with no new modulus and an empty list of hashes | |
272 | |
273 These allow the client to pick the testing scenario its wants to simulate. | |
274 | |
275 Args: | |
276 msg: The DeviceAutoEnrollmentRequest message received from the client. | |
277 | |
278 Returns: | |
279 A tuple of HTTP status code and response data to send to the client. | |
280 """ | |
281 auto_enrollment_response = dm.DeviceAutoEnrollmentResponse() | |
282 | |
283 if msg.modulus == 1: | |
284 auto_enrollment_response.hashes.append(SHA256_0) | |
285 elif msg.modulus == 2: | |
286 auto_enrollment_response.modulus = 4 | |
287 elif msg.modulus == 4: | |
288 auto_enrollment_response.modulus = 2 | |
289 elif msg.modulus == 8: | |
290 return (400, 'Server error') | |
291 | |
292 response = dm.DeviceManagementResponse() | |
293 response.auto_enrollment_response.CopyFrom(auto_enrollment_response) | |
294 return (200, response.SerializeToString()) | |
295 | |
257 def SetProtobufMessageField(self, group_message, field, field_value): | 296 def SetProtobufMessageField(self, group_message, field, field_value): |
258 '''Sets a field in a protobuf message. | 297 '''Sets a field in a protobuf message. |
259 | 298 |
260 Args: | 299 Args: |
261 group_message: The protobuf message. | 300 group_message: The protobuf message. |
262 field: The field of the message to set, it should be a member of | 301 field: The field of the message to set, it should be a member of |
263 group_message.DESCRIPTOR.fields. | 302 group_message.DESCRIPTOR.fields. |
264 field_value: The value to set. | 303 field_value: The value to set. |
265 ''' | 304 ''' |
266 if field.label == field.LABEL_REPEATED: | 305 if field.label == field.LABEL_REPEATED: |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
572 return self._registered_tokens.get(dmtoken, None) | 611 return self._registered_tokens.get(dmtoken, None) |
573 | 612 |
574 def UnregisterDevice(self, dmtoken): | 613 def UnregisterDevice(self, dmtoken): |
575 """Unregisters a device identified by the given DM token. | 614 """Unregisters a device identified by the given DM token. |
576 | 615 |
577 Args: | 616 Args: |
578 dmtoken: The device management token provided by the client. | 617 dmtoken: The device management token provided by the client. |
579 """ | 618 """ |
580 if dmtoken in self._registered_tokens.keys(): | 619 if dmtoken in self._registered_tokens.keys(): |
581 del self._registered_tokens[dmtoken] | 620 del self._registered_tokens[dmtoken] |
OLD | NEW |