def _validate_policy(self, retrieved_policy, username): import chrome_device_policy_pb2 import device_management_backend_pb2 response_proto = device_management_backend_pb2.PolicyFetchResponse() response_proto.ParseFromString(retrieved_policy) ownership.assert_has_policy_data(response_proto) poldata = device_management_backend_pb2.PolicyData() poldata.ParseFromString(response_proto.policy_data) ownership.assert_has_device_settings(poldata) ownership.assert_username(poldata, username) polval = chrome_device_policy_pb2.ChromeDeviceSettingsProto() polval.ParseFromString(poldata.policy_value) ownership.assert_new_users(polval, True) ownership.assert_users_on_whitelist(polval, (username,))
def _GenerateDevicePolicyBlob(self, device_policy=None, owner=None): """Generates a signed device policy blob.""" # Fill in the device settings protobuf. device_policy = device_policy or {} owner = owner or constants.CREDENTIALS['$mockowner'][0] settings = dp.ChromeDeviceSettingsProto() for group in settings.DESCRIPTOR.fields: # Create protobuf message for group. group_message = eval('dp.' + group.message_type.name + '()') # Indicates if at least one field was set in |group_message|. got_fields = False # Iterate over fields of the message and feed them from the policy dict. for field in group_message.DESCRIPTOR.fields: field_value = None if field.name in device_policy: got_fields = True field_value = device_policy[field.name] self._SetProtobufMessageField(group_message, field, field_value) if got_fields: settings.__getattribute__(group.name).CopyFrom(group_message) # Fill in the policy data protobuf. policy_data = dm.PolicyData() policy_data.policy_type = 'google/chromeos/device' policy_data.policy_value = settings.SerializeToString() policy_data.username = owner serialized_policy_data = policy_data.SerializeToString() # Fill in the device management response protobuf. response = dm.DeviceManagementResponse() fetch_response = response.policy_response.response.add() fetch_response.policy_data = serialized_policy_data fetch_response.policy_data_signature = ( self._private_key.hashAndSign(serialized_policy_data).tostring()) self._device_policy_blob = fetch_response.SerializeToString()
def compare_policy_response(policy_response, owner=None, guests=None, new_users=None, roaming=None, whitelist=None): """Check the contents of |policy_response| against given args. Deserializes |policy_response| into a PolicyFetchResponse protobuf, with an embedded (serialized) PolicyData protobuf that embeds a (serialized) ChromeDeviceSettingsProto, and checks to see if this protobuf turducken contains the information passed in. @param policy_response: string serialization of a PolicyData protobuf. @param owner: string representing the owner's name/account. @param guests: boolean indicating whether guests should be allowed. @param new_users: boolean indicating if user pods are on login screen. @param roaming: boolean indicating whether data roaming is enabled. @param whitelist: list of accounts that are allowed to log in. @return True if |policy_response| has all the provided data, else False. """ import chrome_device_policy_pb2 import device_management_backend_pb2 response_proto = device_management_backend_pb2.PolicyFetchResponse() response_proto.ParseFromString(policy_response) ownership.assert_has_policy_data(response_proto) data_proto = device_management_backend_pb2.PolicyData() data_proto.ParseFromString(response_proto.policy_data) ownership.assert_has_device_settings(data_proto) if owner: ownership.assert_username(data_proto, owner) settings = chrome_device_policy_pb2.ChromeDeviceSettingsProto() settings.ParseFromString(data_proto.policy_value) if guests: ownership.assert_guest_setting(settings, guests) if new_users: ownership.assert_show_users(settings, new_users) if roaming: ownership.assert_roaming(settings, roaming) if whitelist: ownership.assert_new_users(settings, False) ownership.assert_users_on_whitelist(settings, whitelist)
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 PolicyFetchRequest message received from the client. Returns: A tuple of HTTP status code and response data to send to the client. """ # Check the GAIA token. auth = self.CheckGoogleLogin() if not auth: return (403, 'No authorization') chrome_initial_settings = dm.ChromeInitialSettingsProto() if ('*' in self._server.policy['managed_users'] or auth in self._server.policy['managed_users']): chrome_initial_settings.enrollment_provision = ( dm.ChromeInitialSettingsProto.MANAGED) else: 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() fetch_response = response.policy_response.response.add() fetch_response.policy_data = (policy_data.SerializeToString()) self.DumpMessage('Response', response) return (200, response.SerializeToString())
def build_policy_data(owner=None, guests=None, new_users=None, roaming=None, whitelist=None): """Generate and serialize a populated device policy protobuffer. Creates a PolicyData protobuf, with an embedded ChromeDeviceSettingsProto, containing the information passed in. @param owner: string representing the owner's name/account. @param guests: boolean indicating whether guests should be allowed. @param new_users: boolean indicating if user pods are on login screen. @param roaming: boolean indicating whether data roaming is enabled. @param whitelist: list of accounts that are allowed to log in. @return serialization of the PolicyData proto that we build. """ import chrome_device_policy_pb2 import device_management_backend_pb2 data_proto = device_management_backend_pb2.PolicyData() data_proto.policy_type = ownership.POLICY_TYPE if owner: data_proto.username = owner settings = chrome_device_policy_pb2.ChromeDeviceSettingsProto() if guests: settings.guest_mode_enabled.guest_mode_enabled = guests if new_users: settings.show_user_names.show_user_names = new_users if roaming: settings.data_roaming_enabled.data_roaming_enabled = roaming if whitelist: settings.allow_new_users.allow_new_users = False for user in whitelist: settings.user_whitelist.user_whitelist.append(user) data_proto.policy_value = settings.SerializeToString() return data_proto.SerializeToString()
def ProcessCloudPolicy(self, msg, token_info, response): """Handles a cloud policy request. (New protocol for policy requests.) Encodes the policy into protobuf representation, signs it and constructs the response. Args: msg: The CloudPolicyRequest message received from the client. token_info: the token extracted from the request. response: A PolicyFetchResponse message that should be filled with the response data. """ if msg.machine_id: self.server.UpdateMachineId(token_info['device_token'], msg.machine_id) # Response is only given if the scope is specified in the config file. # Normally 'google/chromeos/device', 'google/chromeos/user' and # 'google/chromeos/publicaccount' should be accepted. policy = self.server.GetPolicies() policy_value = '' policy_key = msg.policy_type if msg.settings_entity_id: policy_key += '/' + msg.settings_entity_id if msg.policy_type in token_info['allowed_policy_types']: if (msg.policy_type == 'google/chromeos/user' or msg.policy_type == 'google/chrome/user' or msg.policy_type == 'google/chromeos/publicaccount'): settings = cp.CloudPolicySettings() payload = self.server.ReadPolicyFromDataDir( policy_key, settings) if payload is None: self.GatherUserPolicySettings(settings, policy.get(policy_key, {})) payload = settings.SerializeToString() elif dp is not None and msg.policy_type == 'google/chromeos/device': settings = dp.ChromeDeviceSettingsProto() payload = self.server.ReadPolicyFromDataDir( policy_key, settings) if payload is None: self.GatherDevicePolicySettings(settings, policy.get(policy_key, {})) payload = settings.SerializeToString() elif msg.policy_type == 'google/chrome/extension': settings = ep.ExternalPolicyData() payload = self.server.ReadPolicyFromDataDir( policy_key, settings) if payload is None: payload = self.CreatePolicyForExternalPolicyData( policy_key) else: response.error_code = 400 response.error_message = 'Invalid policy type' return else: response.error_code = 400 response.error_message = 'Request not allowed for the token used' return # Sign with 'current_key_index', defaulting to key 0. signing_key = None req_key = None current_key_index = policy.get('current_key_index', 0) nkeys = len(self.server.keys) if (msg.signature_type == dm.PolicyFetchRequest.SHA1_RSA and current_key_index in range(nkeys)): signing_key = self.server.keys[current_key_index] if msg.public_key_version in range(1, nkeys + 1): # requested key exists, use for signing and rotate. req_key = self.server.keys[msg.public_key_version - 1]['private_key'] # Fill the policy data protobuf. policy_data = dm.PolicyData() policy_data.policy_type = msg.policy_type policy_data.timestamp = int(time.time() * 1000) policy_data.request_token = token_info['device_token'] policy_data.policy_value = payload policy_data.machine_name = token_info['machine_name'] policy_data.valid_serial_number_missing = (token_info['machine_id'] in BAD_MACHINE_IDS) policy_data.settings_entity_id = msg.settings_entity_id policy_data.service_account_identity = policy.get( 'service_account_identity', 'policy_testserver.py-service_account_identity') invalidation_source = policy.get('invalidation_source') if invalidation_source is not None: policy_data.invalidation_source = invalidation_source # Since invalidation_name is type bytes in the proto, the Unicode name # provided needs to be encoded as ASCII to set the correct byte pattern. invalidation_name = policy.get('invalidation_name') if invalidation_name is not None: policy_data.invalidation_name = invalidation_name.encode('ascii') if signing_key: policy_data.public_key_version = current_key_index + 1 if msg.policy_type == 'google/chromeos/publicaccount': policy_data.username = msg.settings_entity_id else: # For regular user/device policy, there is no way for the testserver to # know the user name belonging to the GAIA auth token we received (short # of actually talking to GAIA). To address this, we read the username from # the policy configuration dictionary, or use a default. policy_data.username = policy.get('policy_user', '*****@*****.**') policy_data.device_id = token_info['device_id'] signed_data = policy_data.SerializeToString() response.policy_data = signed_data if signing_key: response.policy_data_signature = ( signing_key['private_key'].hashAndSign(signed_data).tostring()) if msg.public_key_version != current_key_index + 1: response.new_public_key = signing_key['public_key'] if req_key: response.new_public_key_signature = (req_key.hashAndSign( response.new_public_key).tostring()) self.DumpMessage('Response', response) return (200, response.SerializeToString())
def ProcessCloudPolicy(self, msg): """Handles a cloud policy request. (New protocol for policy requests.) Checks for authorization, encodes the policy into protobuf representation, signs it and constructs the repsonse. Args: msg: The CloudPolicyRequest message received from the client. Returns: A tuple of HTTP status code and response data to send to the client. """ token_info, error = self.CheckToken() if not token_info: return error if msg.machine_id: self.server.UpdateMachineId(token_info['device_token'], msg.machine_id) # Response is only given if the scope is specified in the config file. # Normally 'google/chromeos/device', 'google/chromeos/user' and # 'google/chromeos/publicaccount' should be accepted. policy = self.server.GetPolicies() policy_value = '' policy_key = msg.policy_type if msg.settings_entity_id: policy_key += '/' + msg.settings_entity_id if msg.policy_type in token_info['allowed_policy_types']: if (msg.policy_type == 'google/chromeos/user' or msg.policy_type == 'google/chrome/user' or msg.policy_type == 'google/chromeos/publicaccount'): settings = cp.CloudPolicySettings() payload = self.server.ReadPolicyFromDataDir(policy_key, settings) if payload is None: self.GatherUserPolicySettings(settings, policy.get(policy_key, {})) payload = settings.SerializeToString() elif msg.policy_type == 'google/chromeos/device': settings = dp.ChromeDeviceSettingsProto() payload = self.server.ReadPolicyFromDataDir(policy_key, settings) if payload is None: self.GatherDevicePolicySettings(settings, policy.get(policy_key, {})) payload = settings.SerializeToString() # Sign with 'current_key_index', defaulting to key 0. signing_key = None req_key = None current_key_index = policy.get('current_key_index', 0) nkeys = len(self.server.keys) if (msg.signature_type == dm.PolicyFetchRequest.SHA1_RSA and current_key_index in range(nkeys)): signing_key = self.server.keys[current_key_index] if msg.public_key_version in range(1, nkeys + 1): # requested key exists, use for signing and rotate. req_key = self.server.keys[msg.public_key_version - 1]['private_key'] # Fill the policy data protobuf. policy_data = dm.PolicyData() policy_data.policy_type = msg.policy_type policy_data.timestamp = int(time.time() * 1000) policy_data.request_token = token_info['device_token'] policy_data.policy_value = payload policy_data.machine_name = token_info['machine_name'] policy_data.valid_serial_number_missing = ( token_info['machine_id'] in BAD_MACHINE_IDS) policy_data.settings_entity_id = msg.settings_entity_id if signing_key: policy_data.public_key_version = current_key_index + 1 if msg.policy_type == 'google/chromeos/publicaccount': policy_data.username = msg.settings_entity_id else: # For regular user/device policy, there is no way for the testserver to # know the user name belonging to the GAIA auth token we received (short # of actually talking to GAIA). To address this, we read the username from # the policy configuration dictionary, or use a default. policy_data.username = policy.get('policy_user', '*****@*****.**') policy_data.device_id = token_info['device_id'] signed_data = policy_data.SerializeToString() response = dm.DeviceManagementResponse() fetch_response = response.policy_response.response.add() fetch_response.policy_data = signed_data if signing_key: fetch_response.policy_data_signature = ( signing_key['private_key'].hashAndSign(signed_data).tostring()) if msg.public_key_version != current_key_index + 1: fetch_response.new_public_key = signing_key['public_key'] if req_key: fetch_response.new_public_key_signature = ( req_key.hashAndSign(fetch_response.new_public_key).tostring()) self.DumpMessage('Response', response) return (200, response.SerializeToString())
def ProcessCloudPolicy(self, msg): """Handles a cloud policy request. (New protocol for policy requests.) Checks for authorization, encodes the policy into protobuf representation, signs it and constructs the repsonse. Args: msg: The CloudPolicyRequest message received from the client. Returns: A tuple of HTTP status code and response data to send to the client. """ token_info, error = self.CheckToken() if not token_info: return error if msg.machine_id: self._server.UpdateMachineId(token_info['device_token'], msg.machine_id) # Response is only given if the scope is specified in the config file. # Normally 'google/chromeos/device' and 'google/chromeos/user' should be # accepted. policy = self._server.GetPolicies() policy_value = '' if (msg.policy_type in token_info['allowed_policy_types'] and msg.policy_type in policy): if msg.policy_type == 'google/chromeos/user': settings = cp.CloudPolicySettings() self.GatherUserPolicySettings(settings, policy[msg.policy_type]) policy_value = settings.SerializeToString() elif msg.policy_type == 'google/chromeos/device': settings = dp.ChromeDeviceSettingsProto() self.GatherDevicePolicySettings(settings, policy[msg.policy_type]) policy_value = settings.SerializeToString() # Figure out the key we want to use. If multiple keys are configured, the # server will rotate through them in a round-robin fashion. signing_key = None req_key = None key_version = 1 nkeys = len(self._server.keys) if msg.signature_type == dm.PolicyFetchRequest.SHA1_RSA and nkeys > 0: if msg.public_key_version in range(1, nkeys + 1): # requested key exists, use for signing and rotate. req_key = self._server.keys[msg.public_key_version - 1]['private_key'] key_version = (msg.public_key_version % nkeys) + 1 signing_key = self._server.keys[key_version - 1] # Fill the policy data protobuf. policy_data = dm.PolicyData() policy_data.policy_type = msg.policy_type policy_data.timestamp = int(time.time() * 1000) policy_data.request_token = token_info['device_token'] policy_data.policy_value = policy_value policy_data.machine_name = token_info['machine_name'] policy_data.valid_serial_number_missing = ( token_info['machine_id'] in BAD_MACHINE_IDS) if signing_key: policy_data.public_key_version = key_version policy_data.username = self._server.username policy_data.device_id = token_info['device_id'] signed_data = policy_data.SerializeToString() response = dm.DeviceManagementResponse() fetch_response = response.policy_response.response.add() fetch_response.policy_data = signed_data if signing_key: fetch_response.policy_data_signature = ( signing_key['private_key'].hashAndSign(signed_data).tostring()) if msg.public_key_version != key_version: fetch_response.new_public_key = signing_key['public_key'] if req_key: fetch_response.new_public_key_signature = ( req_key.hashAndSign(fetch_response.new_public_key).tostring()) self.DumpMessage('Response', response) return (200, response.SerializeToString())