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):])
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]
def _CreateRequest(self, url, data=None): """Creates a new urllib request.""" req = fancy_urllib.FancyRequest(url, data=data) if self.host_override: req.add_header("Host", self.host_override) for key, value in self.extra_headers.iteritems(): req.add_header(key, value) return req
def BuildClientLoginOpener(hostname, credentials): """Produce an urllib2 OpenerDirective that's logged in by client login. Args: hostname: host name for server credentials: A tuple of (email, password). Note: if necessary, "password" should be an application specific password. Returns: Tuple of (urllib2.OpenerDirective, cookielib.CookieJar) . Raises: AuthenticationError: when authentication fails. """ cookiejar = cookielib.CookieJar() opener = urllib2.build_opener( urllib2.HTTPCookieProcessor(cookiejar), fancy_urllib.FancyHTTPSHandler(), fancy_urllib.FancyRedirectHandler()) email, password = credentials # Step 1: We get an Auth token from ClientLogin. req = fancy_urllib.FancyRequest( 'https://www.google.com/accounts/ClientLogin', urllib.urlencode({ 'accountType': 'HOSTED_OR_GOOGLE', 'Email': email, 'Passwd': password, 'service': 'ah', 'source': 'cauliflowervest', }) ) try: response = opener.open(req) except urllib2.HTTPError, e: error_body = e.read() # TODO(user): Consider more failure cases. if 'Error=BadAuthentication' in error_body: raise AuthenticationError('Bad email or password.') elif 'Error=CaptchaRequired' in error_body: # TODO(user): Provide a link to the page where users can fix this: # https://www.google.com/accounts/DisplayUnlockCaptcha raise AuthenticationError( 'Server responded with captcha request; captchas unsupported.') else: raise AuthenticationError('Authentication: Could not get service token.')
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))
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)
def _FetchXsrfToken(self, action): request = fancy_urllib.FancyRequest(self.xsrf_url % action) request.set_ssl_info(ca_certs=self._ca_certs_file) response = self._RetryRequest(request, 'Fetching XSRF token') return response.read()
else: raise AuthenticationError('Authentication: Could not get service token.') try: response_body = response.read() response_dict = dict(x.split('=') for x in response_body.splitlines() if x) assert 'Auth' in response_dict except AssertionError: raise AuthenticationError('Authentication: Service token missing.') # Step 2: We pass that token to App Engine, which responds with a cookie. params = { 'auth': response_dict['Auth'], 'continue': '', } req = fancy_urllib.FancyRequest( 'https://%s/_ah/login?%s' % (hostname, urllib.urlencode(params))) try: response = opener.open(req) except urllib2.HTTPError: logging.exception('HTTPError while obtaining cookie from ClientLogin.') raise AuthenticationError('Authentication: Could not get cookie.') return opener class CauliflowerVestClient(object): """Client to interact with the CauliflowerVest service.""" ESCROW_PATH = None # String path to escrow to, set by subclasses.