Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(798)

Unified Diff: net/tools/testserver/device_management.py

Issue 6537020: Update policy backend and testserver for the newest policy protocol (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: 5 Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/tools/testserver/device_management.py
diff --git a/net/tools/testserver/device_management.py b/net/tools/testserver/device_management.py
index ccf1ac8a51ff68e798657c56cc6909811c377874..bd23cc0b34412a4f6e1f923a5281f8e6851240f9 100644
--- a/net/tools/testserver/device_management.py
+++ b/net/tools/testserver/device_management.py
@@ -61,6 +61,9 @@ except ImportError:
import device_management_backend_pb2 as dm
import cloud_policy_pb2 as cp
+# TODO(gfeher): Remove before commit.
Mattias Nissler (ping if slow) 2011/02/21 14:55:27 good idea :)
+LOG_FILENAME = '/dev/stdout'
+logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
class RequestHandler(object):
"""Decodes and handles device management requests from clients.
@@ -117,16 +120,18 @@ class RequestHandler(object):
self.DumpMessage('Request', rmsg)
request_type = self.GetUniqueParam('request')
+ if (self.GetUniqueParam('devicetype') != '2' or
Mattias Nissler (ping if slow) 2011/02/21 14:55:27 Is that devicetype parameter from a discussion wit
gfeher 2011/02/22 15:57:29 Maybe. Hong had added some server-side requirement
+ self.GetUniqueParam('apptype') != 'Chrome' or
+ (request_type != 'ping' and
+ len(self.GetUniqueParam('deviceid')) >= 64) or
+ len(self.GetUniqueParam('agent')) >= 64):
+ return (400, 'Invalid request parameter')
if request_type == 'register':
return self.ProcessRegister(rmsg.register_request)
elif request_type == 'unregister':
return self.ProcessUnregister(rmsg.unregister_request)
- elif request_type == 'policy':
- return self.ProcessPolicy(rmsg.policy_request)
- elif request_type == 'cloud_policy':
- return self.ProcessCloudPolicyRequest(rmsg.cloud_policy_request)
- elif request_type == 'managed_check':
- return self.ProcessManagedCheck(rmsg.managed_check_request)
+ elif request_type == 'policy' or request_type == 'ping':
+ return self.ProcessPolicy(rmsg.policy_request, request_type)
else:
return (400, 'Invalid request parameter')
@@ -140,12 +145,6 @@ class RequestHandler(object):
return None
return match.group(1)
- def GetDeviceName(self):
- """Returns the name for the currently authenticated device based on its
- device id.
- """
- return 'chromeos-' + self.GetUniqueParam('deviceid')
-
def ProcessRegister(self, msg):
"""Handles a register request.
@@ -166,13 +165,16 @@ class RequestHandler(object):
if not device_id:
return (400, 'Missing device identifier')
- # Register the device and create a token.
- dmtoken = self._server.RegisterDevice(device_id)
+ token_info = self._server.RegisterDevice(device_id,
+ msg.machine_id,
+ msg.type)
# Send back the reply.
response = dm.DeviceManagementResponse()
response.error = dm.DeviceManagementResponse.SUCCESS
- response.register_response.device_management_token = dmtoken
+ response.register_response.device_management_token = (
+ token_info['device_token'])
+ response.register_response.machine_name = token_info['machine_name']
self.DumpMessage('Response', response)
@@ -207,51 +209,48 @@ class RequestHandler(object):
return (200, response.SerializeToString())
- def ProcessManagedCheck(self, msg):
- """Handles a 'managed check' request.
+ def ProcessInitialPolicy(self, msg):
+ """Handles a 'preregister policy' request.
Queries the list of managed users and responds the client if their user
is managed or not.
Args:
- msg: The ManagedCheckRequest message received from the client.
+ msg: The PolicyFetchRequest message received from the client.
Returns:
A tuple of HTTP status code and response data to send to the client.
"""
- # Check the management token.
+ # Check the GAIA token.
auth = self.CheckGoogleLogin()
if not auth:
return (403, 'No authorization')
- managed_check_response = dm.ManagedCheckResponse()
+ chrome_initial_settings = dm.ChromeInitialSettingsProto()
if ('*' in self._server.policy['managed_users'] or
auth in self._server.policy['managed_users']):
- managed_check_response.mode = dm.ManagedCheckResponse.MANAGED;
+ chrome_initial_settings.enrollment_provision = (
+ dm.ChromeInitialSettingsProto.MANAGED);
else:
- managed_check_response.mode = dm.ManagedCheckResponse.UNMANAGED;
+ chrome_initial_settings.enrollment_provision = (
+ dm.ChromeInitialSettingsProto.UNMANAGED);
+
+ policy_data = dm.PolicyData()
+ policy_data.policy_type = msg.policy_type
+ policy_data.policy_value = chrome_initial_settings.SerializeToString()
# Prepare and send the response.
response = dm.DeviceManagementResponse()
response.error = dm.DeviceManagementResponse.SUCCESS
- response.managed_check_response.CopyFrom(managed_check_response)
+ fetch_response = response.policy_response.response.add()
+ fetch_response.policy_data = (
+ policy_data.SerializeToString())
self.DumpMessage('Response', response)
return (200, response.SerializeToString())
- def ProcessPolicy(self, msg):
- """Handles a policy request.
-
- Checks for authorization, encodes the policy into protobuf representation
- and constructs the response.
-
- Args:
- msg: The DevicePolicyRequest message received from the client.
-
- Returns:
- A tuple of HTTP status code and response data to send to the client.
- """
+ def ProcessDevicePolicy(self, msg):
# Check the management token.
token, response = self.CheckToken()
if not token:
@@ -264,8 +263,8 @@ class RequestHandler(object):
# Respond only if the client requested policy for the cros/device scope,
# since that's where chrome policy is supposed to live in.
- if msg.policy_scope in self._server.policy:
- policy = self._server.policy[msg.policy_scope]['mandatory']
+ if msg.policy_scope == 'chromeos/device':
+ policy = self._server.policy['google/chromeos/user']['mandatory']
setting = response.policy_response.setting.add()
setting.policy_key = 'chrome-policy'
policy_value = dm.GenericSetting()
@@ -293,6 +292,35 @@ class RequestHandler(object):
return (200, response.SerializeToString())
+ def ProcessPolicy(self, msg, request_type):
+ """Handles a policy request.
+
+ Checks for authorization, encodes the policy into protobuf representation
+ and constructs the response.
+
+ Args:
+ msg: The DevicePolicyRequest message received from the client.
+
+ Returns:
+ A tuple of HTTP status code and response data to send to the client.
+ """
+
+ if msg.request:
+ for request in msg.request:
+ if request.policy_type == 'google/chromeos/unregistered_user':
+ if request_type != 'ping':
+ return (400, 'Invalid request type')
+ return self.ProcessInitialPolicy(request)
+ elif (request.policy_type in
+ ('google/chromeos/user', 'google/chromeos/device')):
+ if request_type != 'policy':
+ return (400, 'Invalid request type')
+ return self.ProcessCloudPolicy(request)
+ else:
+ return (400, 'Invalid policy_type')
Mattias Nissler (ping if slow) 2011/02/21 14:55:27 What about user policy? Have I missed something?
gfeher 2011/02/22 15:57:29 It is handled in self.ProcessCloudPolicy().
+ else:
+ return self.ProcessDevicePolicy(msg)
+
def SetProtobufMessageField(self, group_message, field, field_value):
'''Sets a field in a protobuf message.
@@ -302,23 +330,22 @@ class RequestHandler(object):
group_message.DESCRIPTOR.fields.
field_value: The value to set.
'''
- if field.label == field.LABEL_REPEATED:
+ if field.type == field.TYPE_BOOL:
+ assert type(field_value) == bool
+ elif field.type == field.TYPE_STRING:
+ assert type(field_value) == str
+ elif field.type == field.TYPE_INT64:
+ assert type(field_value) == int
+ elif (field.type == field.TYPE_MESSAGE and
+ field.message_type.name == 'StringList'):
assert type(field_value) == list
- assert field.type == field.TYPE_STRING
- list_field = group_message.__getattribute__(field.name)
+ entries = group_message.__getattribute__(field.name).entries
for list_item in field_value:
- list_field.append(list_item)
+ entries.append(list_item)
+ return
else:
- # Simple cases:
- if field.type == field.TYPE_BOOL:
- assert type(field_value) == bool
- elif field.type == field.TYPE_STRING:
- assert type(field_value) == str
- elif field.type == field.TYPE_INT64:
- assert type(field_value) == int
- else:
- raise Exception('Unknown field type %s' % field.type_name)
- group_message.__setattr__(field.name, field_value)
+ raise Exception('Unknown field type %s' % field.type)
+ group_message.__setattr__(field.name, field_value)
def GatherPolicySettings(self, settings, policies):
'''Copies all the policies from a dictionary into a protobuf of type
@@ -352,7 +379,7 @@ class RequestHandler(object):
if got_fields:
settings.__getattribute__(group.name).CopyFrom(group_message)
- def ProcessCloudPolicyRequest(self, msg):
+ def ProcessCloudPolicy(self, msg):
"""Handles a cloud policy request. (New protocol for policy requests.)
Checks for authorization, encodes the policy into protobuf representation,
@@ -364,37 +391,37 @@ class RequestHandler(object):
Returns:
A tuple of HTTP status code and response data to send to the client.
"""
- token, response = self.CheckToken()
- if not token:
- return response
+
+ token_info, error = self.CheckToken()
+ if not token_info:
+ return error
settings = cp.CloudPolicySettings()
- if msg.policy_scope in self._server.policy:
- # Respond is only given if the scope is specified in the config file.
+ if (msg.policy_type in token_info['allowed_policy_types'] and
+ msg.policy_type in self._server.policy):
+ # Response is only given if the scope is specified in the config file.
# Normally 'chromeos/device' and 'chromeos/user' should be accepted.
self.GatherPolicySettings(settings,
- self._server.policy[msg.policy_scope])
-
- # Construct response
- signed_response = dm.SignedCloudPolicyResponse()
- signed_response.settings.CopyFrom(settings)
- signed_response.timestamp = int(time.time())
- signed_response.request_token = token;
- signed_response.device_name = self.GetDeviceName()
-
- cloud_response = dm.CloudPolicyResponse()
- cloud_response.signed_response = signed_response.SerializeToString()
- signed_data = cloud_response.signed_response
- cloud_response.signature = (
- self._server.private_key.hashAndSign(signed_data).tostring())
- for certificate in self._server.cert_chain:
- cloud_response.certificate_chain.append(
- certificate.writeBytes().tostring())
+ self._server.policy[msg.policy_type])
+
+ policy_data = dm.PolicyData()
+ policy_data.policy_value = settings.SerializeToString()
+ policy_data.policy_type = msg.policy_type
+ policy_data.timestamp = int(time.time() * 1000)
+ policy_data.request_token = token_info['device_token'];
+ policy_data.machine_name = token_info['machine_name']
+ signed_data = policy_data.SerializeToString()
response = dm.DeviceManagementResponse()
response.error = dm.DeviceManagementResponse.SUCCESS
- response.cloud_policy_response.CopyFrom(cloud_response)
+ fetch_response = response.policy_response.response.add()
+ fetch_response.policy_data = signed_data
+ fetch_response.policy_data_signature = (
+ self._server.private_key.hashAndSign(signed_data).tostring())
+ for certificate in self._server.cert_chain:
+ fetch_response.certificate_chain.append(
+ certificate.writeBytes().tostring())
self.DumpMessage('Response', response)
@@ -404,12 +431,13 @@ class RequestHandler(object):
"""Helper for checking whether the client supplied a valid DM token.
Extracts the token from the request and passed to the server in order to
- look up the client. Returns a pair of token and error response. If the token
- is None, the error response is a pair of status code and error message.
+ look up the client.
Returns:
- A pair of DM token and error response. If the token is None, the message
- will contain the error response to send back.
+ A pair of token information record and error response. If the first
+ element is None, then the second contains an error code to send back to
+ the client. Otherwise the first element is the same structure that is
+ returned by LookupToken().
"""
error = None
dmtoken = None
@@ -420,11 +448,14 @@ class RequestHandler(object):
dmtoken = match.group(1)
if not dmtoken:
error = dm.DeviceManagementResponse.DEVICE_MANAGEMENT_TOKEN_INVALID
- elif (not request_device_id or
- not self._server.LookupDevice(dmtoken) == request_device_id):
- error = dm.DeviceManagementResponse.DEVICE_NOT_FOUND
else:
- return (dmtoken, None)
+ token_info = self._server.LookupToken(dmtoken)
+ if (not token_info or
+ not request_device_id or
+ token_info['device_id'] != request_device_id):
+ error = dm.DeviceManagementResponse.DEVICE_NOT_FOUND
+ else:
+ return (token_info, None)
response = dm.DeviceManagementResponse()
response.error = error
@@ -448,7 +479,7 @@ class TestServer(object):
policy_cert_chain: List of paths to X.509 certificate files of the
certificate chain used for signing responses.
"""
- self._registered_devices = {}
+ self._registered_tokens = {}
self.policy = {}
if json is None:
print 'No JSON module, cannot parse policy information'
@@ -485,8 +516,8 @@ class TestServer(object):
handler = RequestHandler(self, path, headers, request)
return handler.HandleRequest()
- def RegisterDevice(self, device_id):
- """Registers a device and generate a DM token for it.
+ def RegisterDevice(self, device_id, machine_id, type=None):
+ """Registers a device or user and generates a DM token for it.
Args:
device_id: The device identifier provided by the client.
@@ -498,11 +529,21 @@ class TestServer(object):
while len(dmtoken_chars) < 32:
dmtoken_chars.append(random.choice('0123456789abcdef'))
dmtoken = ''.join(dmtoken_chars)
- self._registered_devices[dmtoken] = device_id
- return dmtoken
- def LookupDevice(self, dmtoken):
- """Looks up a device by DMToken.
+ self._registered_tokens[dmtoken] = {
+ 'device_id': device_id,
+ 'device_token': dmtoken,
+ 'allowed_policy_types': {
+ dm.DeviceRegisterRequest.USER: ['google/chromeos/user'],
+ dm.DeviceRegisterRequest.DEVICE: ['google/chromeos/device'],
+ dm.DeviceRegisterRequest.TT: ['google/chromeos/user'],
+ }[type],
+ 'machine_name': 'chromeos-' + machine_id,
+ }
+ return self._registered_tokens[dmtoken]
+
+ def LookupToken(self, dmtoken):
+ """Looks up a device or a user by DM token.
Args:
dmtoken: The device management token provided by the client.
@@ -510,7 +551,7 @@ class TestServer(object):
Returns:
The corresponding device identifier or None if not found.
Mattias Nissler (ping if slow) 2011/02/21 14:55:27 You might want to update this comment.
gfeher 2011/02/22 15:57:29 Done.
"""
- return self._registered_devices.get(dmtoken, None)
+ return self._registered_tokens.get(dmtoken, None)
def UnregisterDevice(self, dmtoken):
"""Unregisters a device identified by the given DM token.
@@ -518,5 +559,5 @@ class TestServer(object):
Args:
dmtoken: The device management token provided by the client.
"""
- if dmtoken in self._registered_devices:
- del self._registered_devices[dmtoken]
+ if dmtoken in self._registered_tokens.keys():
+ del self._registered_tokens[dmtoken]

Powered by Google App Engine
This is Rietveld 408576698