def ProcessRegister(self, msg):
        """Handles a register request.

    Checks the query for authorization and device identifier, registers the
    device with the server and constructs a response.

    Args:
      msg: The DeviceRegisterRequest message received from the client.

    Returns:
      A tuple of HTTP status code and response data to send to the client.
    """
        # Check the auth token and device ID.
        match = re.match('GoogleLogin auth=(\\w+)',
                         self._headers.getheader('Authorization', ''))
        if not match:
            return (403, 'No authorization')
        auth_token = match.group(1)

        device_id = self.GetUniqueParam('deviceid')
        if not device_id:
            return (400, 'Missing device identifier')

        # Register the device and create a token.
        dmtoken = self._server.RegisterDevice(device_id)

        # Send back the reply.
        response = dm.DeviceManagementResponse()
        response.error = dm.DeviceManagementResponse.SUCCESS
        response.register_response.device_management_token = dmtoken

        self.DumpMessage('Response', response)

        return (200, response.SerializeToString())
    def ProcessRegister(self, msg):
        """Handles a register request.

    Checks the query for authorization and device identifier, registers the
    device with the server and constructs a response.

    Args:
      msg: The DeviceRegisterRequest message received from the client.

    Returns:
      A tuple of HTTP status code and response data to send to the client.
    """
        # Check the auth token and device ID.
        if not self.CheckGoogleLogin():
            return (403, 'No authorization')

        device_id = self.GetUniqueParam('deviceid')
        if not device_id:
            return (400, 'Missing device identifier')

        token_info = self._server.RegisterDevice(device_id, msg.machine_id,
                                                 msg.type)

        # Send back the reply.
        response = dm.DeviceManagementResponse()
        response.register_response.device_management_token = (
            token_info['device_token'])
        response.register_response.machine_name = token_info['machine_name']

        self.DumpMessage('Response', response)

        return (200, response.SerializeToString())
    def CheckToken(self):
        """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.

    Returns:
      A pair of DM token and error response. If the token is None, the message
      will contain the error response to send back.
    """
        error = None
        dmtoken = None
        request_device_id = self.GetUniqueParam('deviceid')
        match = re.match('GoogleDMToken token=(\\w+)',
                         self._headers.getheader('Authorization', ''))
        if match:
            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)

        response = dm.DeviceManagementResponse()
        response.error = error

        self.DumpMessage('Response', response)

        return (None, (200, response.SerializeToString()))
    def CheckToken(self):
        """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 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
        request_device_id = self.GetUniqueParam('deviceid')
        match = re.match('GoogleDMToken token=(\\w+)',
                         self._headers.getheader('Authorization', ''))
        if match:
            dmtoken = match.group(1)
        if not dmtoken:
            error = dm.DeviceManagementResponse.DEVICE_MANAGEMENT_TOKEN_INVALID
        else:
            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

        self.DumpMessage('Response', response)

        return (None, (200, response.SerializeToString()))
    def ProcessDevicePolicy(self, msg):
        """Handles a policy request that uses the deprecated protcol.
    TODO(gfeher): Remove this when we certainly don't need it.

    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.
    """

        # Check the management token.
        token, response = self.CheckToken()
        if not token:
            return response

        # Stuff the policy dictionary into a response message and send it back.
        response = dm.DeviceManagementResponse()
        response.policy_response.CopyFrom(dm.DevicePolicyResponse())

        # 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 == '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()
            for (key, value) in policy.iteritems():
                entry = policy_value.named_value.add()
                entry.name = key
                entry_value = dm.GenericValue()
                if isinstance(value, bool):
                    entry_value.value_type = dm.GenericValue.VALUE_TYPE_BOOL
                    entry_value.bool_value = value
                elif isinstance(value, int):
                    entry_value.value_type = dm.GenericValue.VALUE_TYPE_INT64
                    entry_value.int64_value = value
                elif isinstance(value, str) or isinstance(value, unicode):
                    entry_value.value_type = dm.GenericValue.VALUE_TYPE_STRING
                    entry_value.string_value = value
                elif isinstance(value, list):
                    entry_value.value_type = dm.GenericValue.VALUE_TYPE_STRING_ARRAY
                    for list_entry in value:
                        entry_value.string_array.append(str(list_entry))
                entry.value.CopyFrom(entry_value)
            setting.policy_value.CopyFrom(policy_value)

        self.DumpMessage('Response', response)

        return (200, response.SerializeToString())
Beispiel #6
0
  def _RegisterAndGetDMToken(self, device):
    """Registers with the TestServer and returns the DMToken fetched.

    Registers for device policy if device is True. Otherwise registers for
    user policy.
    """
    assert self.IsChromeOS()
    type = device and dmb.DeviceRegisterRequest.DEVICE \
                   or dmb.DeviceRegisterRequest.USER
    rstring = self._PostRegisterRequest(type)
    response = dmb.DeviceManagementResponse()
    response.ParseFromString(rstring)
    return response.register_response.device_management_token
Beispiel #7
0
  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 DeviceManagementRequest 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

    key_update_request = msg.device_state_key_update_request
    if len(key_update_request.server_backed_state_key) > 0:
      self.server.UpdateStateKeys(token_info['device_token'],
                                  key_update_request.server_backed_state_key)

    # If this is a |publicaccount| request, get the |username| now and use
    # it in every PolicyFetchResponse produced. This is required to validate
    # policy for extensions in device-local accounts.
    # Unfortunately, the |username| can't be obtained from |msg| because that
    # requires interacting with GAIA.
    username = None
    for request in msg.policy_request.request:
      if request.policy_type == 'google/chromeos/publicaccount':
        username = request.settings_entity_id

    response = dm.DeviceManagementResponse()
    for request in msg.policy_request.request:
      if (request.policy_type in
             ('google/android/user',
              'google/chromeos/device',
              'google/chromeos/publicaccount',
              'google/chromeos/user',
              'google/chrome/user',
              'google/ios/user')):
        fetch_response = response.policy_response.response.add()
        self.ProcessCloudPolicy(request, token_info, fetch_response, username)
      elif request.policy_type == 'google/chrome/extension':
        self.ProcessCloudPolicyForExtensions(
            request, response.policy_response, token_info, username)
      else:
        fetch_response.error_code = 400
        fetch_response.error_message = 'Invalid policy_type'

    return (200, response)
Beispiel #8
0
 def _DMPostRequest(self, request_type, request, headers):
   """Posts a request to the mock DMServer."""
   assert self.IsChromeOS()
   url = self._GetHttpURLForDeviceManagement()
   url += '?' + urllib.urlencode({
     'deviceid': self.device_id,
     'oauth_token': 'dummy_oauth_token_that_is_not_checked_anyway',
     'request': request_type,
     'devicetype': 2,
     'apptype': 'Chrome',
     'agent': 'Chrome',
   })
   response = dm.DeviceManagementResponse()
   response.ParseFromString(urllib2.urlopen(urllib2.Request(
       url, request.SerializeToString(), headers)).read())
   return response
    def ProcessApiAuthorization(self, msg):
        """Handles an API authorization request.

    Args:
      msg: The DeviceServiceApiAccessRequest message received from the client.

    Returns:
      A tuple of HTTP status code and response data to send to the client.
    """
        policy = self.server.GetPolicies()

        # Return the auth code from the config file if it's defined,
        # else return a descriptive default value.
        response = dm.DeviceManagementResponse()
        response.service_api_access_response.auth_code = policy.get(
            'robot_api_auth_code', 'policy_testserver.py-auth_code')

        return (200, response)
Beispiel #10
0
  def _FetchPolicy(self, token, device):
    """Fetches policy from the TestServer, using the given token.

    Token must be a valid token retrieved with _RegisterAndGetDMToken. If
    device is True, fetches signed device policy. Otherwise fetches user policy.
    This method also verifies the response, and returns the first policy fetch
    response.
    """
    assert self.IsChromeOS()
    type = device and 'google/chromeos/device' or 'google/chromeos/user'
    rstring = self._PostPolicyRequest(token=token, type=type,
                                      want_signature=device)
    response = dmb.DeviceManagementResponse()
    response.ParseFromString(rstring)
    fetch_response = response.policy_response.response[0]
    assert fetch_response.policy_data
    assert fetch_response.policy_data_signature
    assert fetch_response.new_public_key
    return fetch_response
    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 DeviceManagementRequest 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

        key_update_request = msg.device_state_key_update_request
        if len(key_update_request.server_backed_state_key) > 0:
            self.server.UpdateStateKeys(
                token_info['device_token'],
                key_update_request.server_backed_state_key)

        response = dm.DeviceManagementResponse()
        for request in msg.policy_request.request:
            fetch_response = response.policy_response.response.add()
            if (request.policy_type
                    in ('google/android/user', 'google/chrome/extension',
                        'google/chromeos/device',
                        'google/chromeos/publicaccount',
                        'google/chromeos/user', 'google/chrome/user',
                        'google/ios/user')):
                if request_type != 'policy':
                    fetch_response.error_code = 400
                    fetch_response.error_message = 'Invalid request type'
                else:
                    self.ProcessCloudPolicy(request, token_info,
                                            fetch_response)
            else:
                fetch_response.error_code = 400
                fetch_response.error_message = 'Invalid policy_type'

        return (200, response)
    def ProcessRegister(self, msg):
        """Handles a register request.

    Checks the query for authorization and device identifier, registers the
    device with the server and constructs a response.

    Args:
      msg: The DeviceRegisterRequest message received from the client.

    Returns:
      A tuple of HTTP status code and response data to send to the client.
    """
        # Check the auth token and device ID.
        auth = self.CheckGoogleLogin()
        if not auth:
            return (403, 'No authorization')

        policy = self.server.GetPolicies()
        if ('*' not in policy['managed_users']
                and auth not in policy['managed_users']):
            return (403, 'Unmanaged')

        device_id = self.GetUniqueParam('deviceid')
        if not device_id:
            return (400, 'Missing device identifier')

        token_info = self.server.RegisterDevice(device_id, msg.machine_id,
                                                msg.type)

        # Send back the reply.
        response = dm.DeviceManagementResponse()
        response.register_response.device_management_token = (
            token_info['device_token'])
        response.register_response.machine_name = token_info['machine_name']
        response.register_response.enrollment_type = token_info[
            'enrollment_mode']

        return (200, response)
Beispiel #13
0
    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 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())
Beispiel #15
0
  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())
Beispiel #16
0
  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())