OLD | NEW |
---|---|
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 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 27 matching lines...) Expand all Loading... | |
38 }, | 38 }, |
39 "google/chromeos/publicaccount/user@example.com" : { | 39 "google/chromeos/publicaccount/user@example.com" : { |
40 "mandatory" : { | 40 "mandatory" : { |
41 "HomepageLocation" : "http://www.chromium.org" | 41 "HomepageLocation" : "http://www.chromium.org" |
42 }, | 42 }, |
43 "recommended" : { | 43 "recommended" : { |
44 } | 44 } |
45 }, | 45 }, |
46 "managed_users" : [ | 46 "managed_users" : [ |
47 "secret123456" | 47 "secret123456" |
48 ] | 48 ], |
49 "current_key_index": 0 | |
49 } | 50 } |
50 | 51 |
51 """ | 52 """ |
52 | 53 |
53 import cgi | 54 import cgi |
54 import hashlib | 55 import hashlib |
55 import logging | 56 import logging |
56 import os | 57 import os |
57 import random | 58 import random |
58 import re | 59 import re |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
448 if msg.policy_type in token_info['allowed_policy_types']: | 449 if msg.policy_type in token_info['allowed_policy_types']: |
449 if (msg.policy_type == 'google/chromeos/user' or | 450 if (msg.policy_type == 'google/chromeos/user' or |
450 msg.policy_type == 'google/chrome/user' or | 451 msg.policy_type == 'google/chrome/user' or |
451 msg.policy_type == 'google/chromeos/publicaccount'): | 452 msg.policy_type == 'google/chromeos/publicaccount'): |
452 settings = cp.CloudPolicySettings() | 453 settings = cp.CloudPolicySettings() |
453 self.GatherUserPolicySettings(settings, policy.get(policy_key, {})) | 454 self.GatherUserPolicySettings(settings, policy.get(policy_key, {})) |
454 elif msg.policy_type == 'google/chromeos/device': | 455 elif msg.policy_type == 'google/chromeos/device': |
455 settings = dp.ChromeDeviceSettingsProto() | 456 settings = dp.ChromeDeviceSettingsProto() |
456 self.GatherDevicePolicySettings(settings, policy.get(policy_key, {})) | 457 self.GatherDevicePolicySettings(settings, policy.get(policy_key, {})) |
457 | 458 |
458 # Figure out the key we want to use. If multiple keys are configured, the | 459 # Sign with 'current_key_index', defaulting to key 0. |
459 # server will rotate through them in a round-robin fashion. | |
460 signing_key = None | 460 signing_key = None |
461 req_key = None | 461 req_key = None |
462 key_version = 1 | 462 current_key_index = policy.get('current_key_index', 0) |
463 nkeys = len(self._server.keys) | 463 nkeys = len(self._server.keys) |
464 if msg.signature_type == dm.PolicyFetchRequest.SHA1_RSA and nkeys > 0: | 464 if (msg.signature_type == dm.PolicyFetchRequest.SHA1_RSA and |
465 current_key_index in range(nkeys)): | |
466 signing_key = self._server.keys[current_key_index] | |
465 if msg.public_key_version in range(1, nkeys + 1): | 467 if msg.public_key_version in range(1, nkeys + 1): |
466 # requested key exists, use for signing and rotate. | 468 # requested key exists, use for signing and rotate. |
467 req_key = self._server.keys[msg.public_key_version - 1]['private_key'] | 469 req_key = self._server.keys[msg.public_key_version - 1]['private_key'] |
468 key_version = (msg.public_key_version % nkeys) + 1 | |
469 signing_key = self._server.keys[key_version - 1] | |
470 | 470 |
471 # Fill the policy data protobuf. | 471 # Fill the policy data protobuf. |
472 policy_data = dm.PolicyData() | 472 policy_data = dm.PolicyData() |
473 policy_data.policy_type = msg.policy_type | 473 policy_data.policy_type = msg.policy_type |
474 policy_data.timestamp = int(time.time() * 1000) | 474 policy_data.timestamp = int(time.time() * 1000) |
475 policy_data.request_token = token_info['device_token'] | 475 policy_data.request_token = token_info['device_token'] |
476 policy_data.policy_value = settings.SerializeToString() | 476 policy_data.policy_value = settings.SerializeToString() |
477 policy_data.machine_name = token_info['machine_name'] | 477 policy_data.machine_name = token_info['machine_name'] |
478 policy_data.valid_serial_number_missing = ( | 478 policy_data.valid_serial_number_missing = ( |
479 token_info['machine_id'] in BAD_MACHINE_IDS) | 479 token_info['machine_id'] in BAD_MACHINE_IDS) |
480 policy_data.settings_entity_id = msg.settings_entity_id | 480 policy_data.settings_entity_id = msg.settings_entity_id |
481 | 481 |
482 if signing_key: | 482 if signing_key: |
483 policy_data.public_key_version = key_version | 483 policy_data.public_key_version = current_key_index + 1 |
484 if msg.policy_type == 'google/chromeos/publicaccount': | 484 if msg.policy_type == 'google/chromeos/publicaccount': |
485 policy_data.username = msg.settings_entity_id | 485 policy_data.username = msg.settings_entity_id |
486 else: | 486 else: |
487 # For regular user/device policy, there is no way for the testserver to | 487 # For regular user/device policy, there is no way for the testserver to |
488 # know the user name belonging to the GAIA auth token we received (short | 488 # know the user name belonging to the GAIA auth token we received (short |
489 # of actually talking to GAIA). To address this, we read the username from | 489 # of actually talking to GAIA). To address this, we read the username from |
490 # the policy configuration dictionary, or use a default. | 490 # the policy configuration dictionary, or use a default. |
491 policy_data.username = policy.get('policy_user', 'user@example.com') | 491 policy_data.username = policy.get('policy_user', 'user@example.com') |
492 policy_data.device_id = token_info['device_id'] | 492 policy_data.device_id = token_info['device_id'] |
493 signed_data = policy_data.SerializeToString() | 493 signed_data = policy_data.SerializeToString() |
494 | 494 |
495 response = dm.DeviceManagementResponse() | 495 response = dm.DeviceManagementResponse() |
496 fetch_response = response.policy_response.response.add() | 496 fetch_response = response.policy_response.response.add() |
497 fetch_response.policy_data = signed_data | 497 fetch_response.policy_data = signed_data |
498 if signing_key: | 498 if signing_key: |
499 fetch_response.policy_data_signature = ( | 499 fetch_response.policy_data_signature = ( |
500 signing_key['private_key'].hashAndSign(signed_data).tostring()) | 500 signing_key['private_key'].hashAndSign(signed_data).tostring()) |
501 if msg.public_key_version != key_version: | 501 if msg.public_key_version != current_key_index + 1: |
502 fetch_response.new_public_key = signing_key['public_key'] | 502 fetch_response.new_public_key = signing_key['public_key'] |
503 if req_key: | 503 if req_key: |
504 fetch_response.new_public_key_signature = ( | 504 fetch_response.new_public_key_signature = ( |
505 req_key.hashAndSign(fetch_response.new_public_key).tostring()) | 505 req_key.hashAndSign(fetch_response.new_public_key).tostring()) |
506 | 506 |
507 self.DumpMessage('Response', response) | 507 self.DumpMessage('Response', response) |
508 | 508 |
509 return (200, response.SerializeToString()) | 509 return (200, response.SerializeToString()) |
510 | 510 |
511 def CheckToken(self): | 511 def CheckToken(self): |
(...skipping 30 matching lines...) Expand all Loading... | |
542 | 542 |
543 return (None, (error, 'Server error %d' % error)) | 543 return (None, (error, 'Server error %d' % error)) |
544 | 544 |
545 def DumpMessage(self, label, msg): | 545 def DumpMessage(self, label, msg): |
546 """Helper for logging an ASCII dump of a protobuf message.""" | 546 """Helper for logging an ASCII dump of a protobuf message.""" |
547 logging.debug('%s\n%s' % (label, str(msg))) | 547 logging.debug('%s\n%s' % (label, str(msg))) |
548 | 548 |
549 class TestServer(object): | 549 class TestServer(object): |
550 """Handles requests and keeps global service state.""" | 550 """Handles requests and keeps global service state.""" |
551 | 551 |
552 def __init__(self, policy_path, private_key_paths): | 552 def __init__(self, policy_path): |
553 """Initializes the server. | 553 """Initializes the server. |
554 | 554 |
555 Args: | 555 Args: |
556 policy_path: Names the file to read JSON-formatted policy from. | 556 policy_path: Names the file to read JSON-formatted policy from. |
557 private_key_paths: List of paths to read private keys from. | |
558 """ | 557 """ |
559 self._registered_tokens = {} | 558 self._registered_tokens = {} |
560 self.policy_path = policy_path | 559 self.policy_path = policy_path |
561 | 560 |
561 # Generate 2 private keys. | |
562 self.keys = [] | 562 self.keys = [] |
563 if private_key_paths: | 563 for i in range(2): |
564 # Load specified keys from the filesystem. | 564 key = tlslite.api.generateRSAKey(512) |
Mattias Nissler (ping if slow)
2013/02/07 14:12:07
I'd hate to loose the ability to use keys passed o
Joao da Silva
2013/02/07 16:32:00
Reverted.
| |
565 for key_path in private_key_paths: | |
566 try: | |
567 key = tlslite.api.parsePEMKey(open(key_path).read(), private=True) | |
568 except IOError: | |
569 print 'Failed to load private key from %s' % key_path | |
570 continue | |
571 | |
572 assert key is not None | |
573 self.keys.append({ 'private_key' : key }) | |
574 else: | |
575 # Generate a key if none were specified. | |
576 key = tlslite.api.generateRSAKey(1024) | |
577 assert key is not None | 565 assert key is not None |
578 self.keys.append({ 'private_key' : key }) | 566 self.keys.append({ 'private_key' : key }) |
579 | 567 |
580 # Derive the public keys from the loaded private keys. | 568 # Derive the public keys from the generated private keys. |
581 for entry in self.keys: | 569 for entry in self.keys: |
582 key = entry['private_key'] | 570 key = entry['private_key'] |
583 | 571 |
584 algorithm = asn1der.Sequence( | 572 algorithm = asn1der.Sequence( |
585 [ asn1der.Data(asn1der.OBJECT_IDENTIFIER, PKCS1_RSA_OID), | 573 [ asn1der.Data(asn1der.OBJECT_IDENTIFIER, PKCS1_RSA_OID), |
586 asn1der.Data(asn1der.NULL, '') ]) | 574 asn1der.Data(asn1der.NULL, '') ]) |
587 rsa_pubkey = asn1der.Sequence([ asn1der.Integer(key.n), | 575 rsa_pubkey = asn1der.Sequence([ asn1der.Integer(key.n), |
588 asn1der.Integer(key.e) ]) | 576 asn1der.Integer(key.e) ]) |
589 pubkey = asn1der.Sequence([ algorithm, asn1der.Bitstring(rsa_pubkey) ]) | 577 pubkey = asn1der.Sequence([ algorithm, asn1der.Bitstring(rsa_pubkey) ]) |
590 entry['public_key'] = pubkey; | 578 entry['public_key'] = pubkey; |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
676 return self._registered_tokens.get(dmtoken, None) | 664 return self._registered_tokens.get(dmtoken, None) |
677 | 665 |
678 def UnregisterDevice(self, dmtoken): | 666 def UnregisterDevice(self, dmtoken): |
679 """Unregisters a device identified by the given DM token. | 667 """Unregisters a device identified by the given DM token. |
680 | 668 |
681 Args: | 669 Args: |
682 dmtoken: The device management token provided by the client. | 670 dmtoken: The device management token provided by the client. |
683 """ | 671 """ |
684 if dmtoken in self._registered_tokens.keys(): | 672 if dmtoken in self._registered_tokens.keys(): |
685 del self._registered_tokens[dmtoken] | 673 del self._registered_tokens[dmtoken] |
OLD | NEW |