def refresh_local_token(server): cur_time = int(time.time()) access_token, expires_at, refresh_token = get_storage() if cur_time < expires_at - 10: return access_token access_token, expires_in = make_refresh_post(server, refresh_token) if not (access_token and expires_in): raise AuthenticationException( "Authentication failed and returned an empty token.") update_storage(access_token, expires_in, refresh_token) return access_token
def update_storage(access_token, expires_in, refresh_token): if not (access_token and expires_in and refresh_token): raise AuthenticationException( "Authentication failed and returned an empty token.") cur_time = int(time.time()) create_config_directory() with open(REFRESH_FILE, 'wb') as fp: pickle.dump({ 'access_token': access_token, 'expires_at': cur_time + expires_in, 'refresh_token': refresh_token }, fp)
def pick_free_port(hostname=REDIRECT_HOST, port=0): """ Try to bind a port. Default=0 selects a free port. """ import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: s.bind((hostname, port)) # port=0 finds an open port except OSError as e: log.warning("Could not bind to %s:%s %s", hostname, port, e) if port == 0: print('Unable to find an open port for authentication.') raise AuthenticationException(e) else: return pick_free_port(hostname, 0) addr, port = s.getsockname() s.close() return port
def refresh_local_token(server): try: cur_time = int(time.time()) access_token, expires_at, refresh_token = get_storage() if cur_time < expires_at - 10: return access_token access_token, expires_in = make_refresh_post(server, refresh_token) if not access_token and expires_in: raise AuthenticationException( "Authentication failed and returned an empty token.") update_storage(access_token, expires_in, refresh_token) return access_token except IOError: return False except AuthenticationException as e: raise e # Let the main script handle this error except Exception: return False
def authenticate(force=False): """ Returns an oauth token that can be passed to the server for identification. """ if not force: try: cur_time = int(time.time()) access_token, expires_at, refresh_token = get_storage() if cur_time < expires_at - 10: return access_token access_token, expires_in = make_refresh_post(refresh_token) if not access_token and expires_in: raise AuthenticationException( "Authentication failed and returned an empty token.") update_storage(access_token, expires_in, refresh_token) return access_token except IOError as _: print('Performing authentication') except AuthenticationException as e: raise e # Let the main script handle this error except Exception as _: print('Performing authentication') check_ssl() print("Please enter your bCourses email.") email = input("bCourses email: ") host_name = REDIRECT_HOST try: port_number = pick_free_port(port=REDIRECT_PORT) except AuthenticationException as e: # Could not bind to REDIRECT_HOST:0, try localhost instead host_name = 'localhost' port_number = pick_free_port(host_name, 0) redirect_uri = "http://{0}:{1}/".format(host_name, port_number) log.info("Authentication server running on {}".format(redirect_uri)) c = Client(auth_endpoint='https://accounts.google.com/o/oauth2/auth', client_id=CLIENT_ID) url = c.auth_uri(scope="profile email", access_type='offline', name='ok-server', redirect_uri=redirect_uri, login_hint=email) webbrowser.open_new(url) done = False access_token = None refresh_token = None expires_in = None auth_error = None class CodeHandler(http.server.BaseHTTPRequestHandler): def send_failure(self, message): self.send_response(400) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write(bytes(failure_page(message), "utf-8")) def do_GET(self): """Respond to the GET request made by the OAuth""" nonlocal access_token, refresh_token, expires_in, auth_error, done path = urlparse(self.path) qs = parse_qs(path.query) try: code = qs['code'][0] code_response = _make_code_post(code, redirect_uri) access_token, refresh_token, expires_in = code_response except KeyError: message = qs.get('error', 'Unknown') log.warning("No auth code provided {}".format(message)) auth_error = message done = True self.send_failure(message) return except Exception as e: # TODO : Catch just SSL errors log.warning("Could not obtain token", exc_info=True) auth_error = e.message done = True self.send_failure(e.message) return done = True self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() actual_email = email try: email_resp = get_student_email(access_token) if email_resp: actual_email = email_resp except Exception as e: # TODO : Catch just SSL errors log.warning("Could not get email from token", exc_info=True) reponse = success_page(SERVER, actual_email, access_token) self.wfile.write(bytes(reponse, "utf-8")) def log_message(self, format, *args): return server_address = (host_name, port_number) try: httpd = http.server.HTTPServer(server_address, CodeHandler) httpd.handle_request() except OSError as e: log.warning("HTTP Server Err {}".format(server_address), exc_info=True) raise if not auth_error: update_storage(access_token, expires_in, refresh_token) return access_token else: print("Authentication error: {}".format(auth_error)) return None