def auth_via_browser(self): """ Handles authentication and authorization. Raises ------ AuthorizationError If the authentication or authorization could not be completed """ self._start_auth_server() self._open_browser(self.callback_url) logger.debug("Waiting for authorization code...") tokens = self.auth_server._wait_for_tokens() self._stop_auth_server() try: refresh_token = tokens["refresh_token"] refresh_expiry = tokens["refresh_token_expires_in"] access_token = tokens["access_token"] access_expiry = tokens["expires_in"] access_time = tokens["access_time"] except KeyError: logger.error("Authorization could not be completed.") raise AuthorizationError("Authorization could not be completed.") r = RefreshToken(token=refresh_token, access_time=access_time, expires_in=refresh_expiry) a = AccessToken(token=access_token, access_time=access_time, expires_in=access_expiry) logger.debug("Refresh and Access tokens received.") return ( r, a, )
def refresh_auth(): global __api__ if __api__ is None: raise AuthorizationError("Default API not found.") else: __api__.refresh_auth() return
def _wait_for_tokens(self): count = 0 while count <= self.retry_count and self.tokens is None: self.handle_request() if self.tokens: return self.tokens else: raise AuthorizationError("The authorization could not be " "completed.")
def _authenticate_wrapper(self, *args, **kwargs): if self.api.auth_valid is True: return func(self, *args, **kwargs) else: if self.api.refresh_valid is False: logger.warning("Need new refresh token.") choice = yn_require("Would you like to authorize a new " "refresh token?") if choice is True: self.api.refresh_auth() else: raise AuthorizationError("Refresh token " "needed for access.") else: self.api.auth.refresh_access_token() if self.api.auth_valid is True: return func(self, *args, **kwargs) else: raise AuthorizationError("Authorization could not be " "completed.")
def refresh_access_token(self): """ Attempts to refresh access token if current is not valid. Updates the cache if new token is received. Raises ------ AuthorizationError If the access token is not successfully refreshed """ if self.cache.refresh_token.valid is False: raise AuthorizationError("Refresh token is not valid.") logger.debug("Attempting to refresh access token...") headers = {'Content-Type': 'application/x-www-form-urlencoded'} data = { 'grant_type': 'refresh_token', 'refresh_token': self.cache.refresh_token.token, 'client_id': self.consumer_key } try: authReply = requests.post( 'https://api.tdameritrade.com/v1/oauth2/' 'token', headers=headers, data=data) now = to_timestamp(datetime.datetime.now()) if authReply.status_code == 400: raise AuthorizationError("Could not refresh access token.") authReply.raise_for_status() json_data = authReply.json() token = json_data["access_token"] expires_in = json_data["expires_in"] except (KeyError, ValueError): logger.error("Error retrieving access token.") raise AuthorizationError("Error retrieving access token.") access_token = AccessToken(token=token, access_time=now, expires_in=expires_in) logger.debug("Successfully refreshed access token.") self.cache.access_token = access_token
def _check_status_codes(self, response): status = response.status_code logger.debug("RESPONSE TEXT (1st 200 chars): %s" % response.text[:200]) if status in [301, 302, 303, 307]: message = "There was an unexpected redirect during your request." raise Redirection(response, message=message) elif status == 400: message = "There was a validation problem with your request." raise ValidationError(response, message=message) elif status == 401: message = "Auth Token invalid." raise AuthorizationError(message) elif status == 403: message = "You are forbidden from accessing this resource." raise ForbiddenAccess(response, message=message) elif status == 404: message = "The requested resource was not found." raise ResourceNotFound(response=response, message=message) elif 401 <= status <= 499: message = "There was a client-side error with your request." raise ClientError(response, message=message) elif 500 <= status <= 599: t = response.text t = re.sub(r"[\n\t\s]*", "", t) t = re.sub(r"\\", "", t) try: import json json_data = json.loads(t) if json_data["error"] == "InvalidApiKey": raise AuthorizationError("Invalid OAuth ID.") except ValueError: pass message = "There was a server-side error with your request." raise ServerError(response, message=message) else: raise TDQueryError(response=response, message="Unknown response code.")
def do_GET(self): if self.path.endswith(".css"): f = open("pyTD/auth/_static/style.css", 'r') self.send_response(200) self.send_header('Content-type', 'text/css') self.end_headers() self.wfile.write(f.read().encode()) f.close() return self._set_headers() path, _, query_string = self.path.partition('?') try: code = parse_qs(query_string)['code'][0] except KeyError: f = codecs.open("pyTD/auth/_static/auth.html", "r", "utf-8") auth = f.read() link = auth.format(self.auth_link) self.wfile.write(link.encode('utf-8')) f.close() else: self.server.auth_code = code headers = {'Content-Type': 'application/x-www-form-urlencoded'} data = {'refresh_token': '', 'grant_type': 'authorization_code', 'access_type': 'offline', 'code': self.server.auth_code, 'client_id': self.server.consumer_key, 'redirect_uri': self.server.callback_url} now = to_timestamp(datetime.datetime.now()) authReply = requests.post('https://api.tdameritrade.com/v1/oauth2/' 'token', headers=headers, data=data) try: json_data = authReply.json() json_data["access_time"] = now self.server._store_tokens(json_data) except ValueError: msg = json.dumps(json_data) logger.Error("Tokens could not be obtained") logger.Error("RESPONSE: %s" % msg) raise AuthorizationError("Authorization could not be " "completed") success = codecs.open("pyTD/auth/_static/success.html", "r", "utf-8") self.wfile.write(success.read().encode()) success.close()