def __init__(self, base_url, opener, headers=None):
     self._metadata = None
     self.base_url = base_url
     self.xsrf_url = util.JoinURL(base_url, self.XSRF_PATH)
     if self.ESCROW_PATH is None:
         raise ValueError(
             'ESCROW_PATH must be set by CauliflowerVestClient subclasses.')
     self.escrow_url = util.JoinURL(base_url, self.ESCROW_PATH)
     self.opener = opener
     self.headers = headers or {}
Exemple #2
0
  def __init__(self, base_url, opener, headers=None):
    self._metadata = None
    self.base_url = base_url
    self.xsrf_url = util.JoinURL(base_url, self.XSRF_PATH)
    if self.ESCROW_PATH is None:
      raise ValueError('ESCROW_PATH must be set by CauliflowerVestClient subclasses.')
    self.escrow_url = util.JoinURL(base_url, self.ESCROW_PATH)
    self.opener = opener
    self.headers = headers or {}

    self._ca_certs_file = settings.ROOT_CA_CERT_CHAIN_PEM_FILE_PATH
    def UploadPassphrase(self, volume_uuid, passphrase):
        """Uploads a volume uuid/passphrase pair with metadata.

    Args:
      volume_uuid: str, UUID of an encrypted volume.
      passphrase: str, passphrase that can be used to unlock the volume.
    Raises:
      RequestError: there was an error uploading to the server.
    """
        xsrf_token = self._FetchXsrfToken(base_settings.SET_PASSPHRASE_ACTION)

        # Ugh, urllib2 only does GET and POST?!
        class PutRequest(fancy_urllib.FancyRequest):
            def __init__(self, *args, **kwargs):
                kwargs.setdefault('headers', {})
                kwargs['headers']['Content-Type'] = 'application/octet-stream'
                fancy_urllib.FancyRequest.__init__(self, *args, **kwargs)
                self._method = 'PUT'

            def get_method(self):  # pylint: disable=g-bad-name
                return 'PUT'

        if not self._metadata:
            self.GetAndValidateMetadata()
        self._metadata['xsrf-token'] = xsrf_token
        url = '%s?%s' % (util.JoinURL(
            self.escrow_url, volume_uuid), urllib.urlencode(self._metadata))

        request = PutRequest(url, data=passphrase)
        request.set_ssl_info(ca_certs=self._ca_certs_file)
        self._RetryRequest(request, 'Uploading passphrase')
Exemple #4
0
    def RetrieveSecret(self, target_id):
        """Fetches and returns the passphrase.

    Args:
      target_id: str, Target ID to fetch the passphrase for.
    Returns:
      str: passphrase.
    Raises:
      RequestError: there was an error downloading the passphrase.
      NotFoundError: no passphrase was found for the given target_id.
    """
        xsrf_token = self._FetchXsrfToken(base_settings.GET_PASSPHRASE_ACTION)
        url = '%s?%s' % (util.JoinURL(self.escrow_url,
                                      urllib.quote(target_id)),
                         urllib.urlencode({'xsrf-token': xsrf_token}))
        request = fancy_urllib.FancyRequest(url)
        request.set_ssl_info(ca_certs=self._ca_certs_file)
        try:
            response = self.opener.open(request)
        except urllib2.URLError as e:  # Parent of urllib2.HTTPError.
            if isinstance(e, urllib2.HTTPError):
                e.msg += ': ' + e.read()
                if e.code == httplib.NOT_FOUND:
                    raise NotFoundError('Failed to retrieve passphrase. %s' %
                                        e)
            raise RequestError('Failed to retrieve passphrase. %s' % e)
        content = response.read()
        if not content.startswith(JSON_PREFIX):
            raise RequestError('Expected JSON prefix missing.')
        data = json.loads(content[len(JSON_PREFIX):])
        return data[self.PASSPHRASE_KEY]
Exemple #5
0
    def IsKeyRotationNeeded(self, target_id, tag='default'):
        """Check whether a key rotation is required.

    Args:
      target_id: str, Target ID.
      tag: str, passphrase tag.
    Raises:
      RequestError: there was an error getting status from server.
    Returns:
      bool: True if a key rotation is required.
    """
        url = '%s?%s' % (util.JoinURL(
            self.base_url, '/api/v1/rekey-required/', self.ESCROW_PATH,
            target_id), urllib.urlencode({'tag': tag}))
        request = fancy_urllib.FancyRequest(url)
        request.set_ssl_info(ca_certs=self._ca_certs_file)
        try:
            response = self.opener.open(request)
        except urllib2.URLError as e:  # Parent of urllib2.HTTPError.
            if isinstance(e, urllib2.HTTPError):
                e.msg += ': ' + e.read()
            raise RequestError('Failed to get status. %s' % e)
        content = response.read()
        if not content.startswith(JSON_PREFIX):
            raise RequestError('Expected JSON prefix missing.')
        return json.loads(content[len(JSON_PREFIX):])
Exemple #6
0
    def RetrievePassphrase(self, volume_uuid):
        """Fetches and returns the FileVault passphrase.

    Args:
      volume_uuid: str, Volume UUID to fetch the keychain for.
    Returns:
      str: passphrase to unlock the keychain.
    Raises:
      DownloadError: there was an error downloading the keychain.
    """
        request = fancy_urllib.FancyRequest(
            util.JoinURL(self.filevault_url, volume_uuid))
        request.set_ssl_info(ca_certs=self._ca_certs_file)
        try:
            response = self.opener.open(request)
        except urllib2.HTTPError, e:
            raise DownloadError('Failed to retrieve passphrase. %s' % str(e))
    def RetrieveSecret(self, volume_uuid):
        """Fetches and returns the passphrase.

    Args:
      volume_uuid: str, Volume UUID to fetch the passphrase for.
    Returns:
      str: passphrase to unlock an encrypted volume.
    Raises:
      RequestError: there was an error downloading the passphrase.
    """
        xsrf_token = self._FetchXsrfToken(base_settings.GET_PASSPHRASE_ACTION)
        url = '%s?%s' % (util.JoinURL(self.escrow_url, volume_uuid),
                         urllib.urlencode({'xsrf-token': xsrf_token}))
        request = fancy_urllib.FancyRequest(url)
        request.set_ssl_info(ca_certs=self._ca_certs_file)
        try:
            response = self.opener.open(request)
        except urllib2.HTTPError, e:
            raise RequestError('Failed to retrieve passphrase. %s' % str(e))
    def IsKeyRotationNeeded(self, target_id, tag='default'):
        """Check whether a key rotation is required.

    Args:
      target_id: str, Target ID.
      tag: str, passphrase tag.
    Raises:
      RequestError: there was an error getting status from server.
    Returns:
      bool: True if a key rotation is required.
    """
        url = '%s?%s' % (util.JoinURL(
            self.base_url, '/api/v1/rekey-required/', self.ESCROW_PATH,
            target_id), urllib.urlencode({'tag': tag}))
        request = fancy_urllib.FancyRequest(url)
        request.set_ssl_info(ca_certs=self._ca_certs_file)
        try:
            response = self.opener.open(request)
        except urllib2.HTTPError, e:
            raise RequestError('Failed to get status. %s' % str(e))
Exemple #9
0
  def VerifyEscrow(self, volume_uuid):
    """Verifies if a Volume UUID has a passphrase escrowed or not.

    Args:
      volume_uuid: str, Volume UUID to verify escrow for.
    Returns:
      Boolean. True if a passphrase is escrowed, False otherwise.
    Raises:
      RequestError: there was an error querying the server.
    """
    request = fancy_urllib.FancyRequest(
        util.JoinURL(self.escrow_url, volume_uuid, '?only_verify_escrow=1'))
    request.set_ssl_info(ca_certs=self._ca_certs_file)
    try:
      self._RetryRequest(request, 'Verifying escrow')
    except urllib2.HTTPError, e:
      if e.code == 404:
        return False
      else:
        raise RequestError('Failed to verify escrow. HTTP %s' % e.code)
Exemple #10
0
    def UploadPassphrase(self, volume_uuid, passphrase):
        """Uploads a FileVault volume uuid/passphrase pair with metadata.

    Args:
      volume_uuid: str, UUID of FileVault encrypted volume.
      passphrase: str, passphrase that can be used to unlock the volume.
    Raises:
      UploadError: there was an error uploading to the server.
    """

        # Ugh, urllib2 only does GET and POST?!
        class PutRequest(fancy_urllib.FancyRequest):
            def __init__(self, *args, **kwargs):
                fancy_urllib.FancyRequest.__init__(self, *args, **kwargs)
                self._method = 'PUT'

            def get_method(self):  # pylint: disable-msg=C6409
                return 'PUT'

        if not self._metadata:
            self.GetAndValidateMetadata()
        url = '%s?%s' % (util.JoinURL(
            self.filevault_url, volume_uuid), urllib.urlencode(self._metadata))

        for try_num in range(self.MAX_TRIES):
            request = PutRequest(url, data=passphrase)
            request.set_ssl_info(ca_certs=self._ca_certs_file)
            try:
                self.opener.open(request)
                break
            except urllib2.HTTPError, e:
                if try_num == self.MAX_TRIES - 1:
                    logging.exception(
                        'Uploading passphrase failed permanently.')
                    raise UploadError(
                        'Uploading passphrase failed permanently: %s', str(e))
                logging.warning(
                    'Uploading passphrase failed with HTTP %s. Retrying ...',
                    e.code)
                time.sleep((try_num + 1) * self.TRY_DELAY_FACTOR)
Exemple #11
0
 def testJoinURLWithTrailingSlashOnLastURLPart(self):
     base_url = 'http://example.com'
     part1 = 'foo'
     part2 = 'bar/'
     out = util.JoinURL(base_url, part1, part2)
     self.assertEqual(out, 'http://example.com/foo/bar/')
Exemple #12
0
 def testJoinURLWithLeadingAndTrailingSlashOnInnerURLPart(self):
     base_url = 'http://example.com'
     part1 = '/foo/'
     part2 = '/bar'
     out = util.JoinURL(base_url, part1, part2)
     self.assertEqual(out, 'http://example.com/foo/bar')
Exemple #13
0
 def testJoinURL(self):
     base_url = 'http://example.com'
     part1 = 'foo'
     part2 = 'bar'
     out = util.JoinURL(base_url, part1, part2)
     self.assertEqual(out, 'http://example.com/foo/bar')