From 700f13f3db1a9d1e3617eafa204459ba3f97ebd0 Mon Sep 17 00:00:00 2001 From: Joe Gregorio Date: Tue, 2 Jul 2013 13:47:15 -0400 Subject: [PATCH] Bring back tools.run(), but only conditionally on gflags. Add a warning that tools.run() is deprecated and will be removed in a future version. Reviewed in https://codereview.appspot.com/9772046/. --- apiclient/sample_tools.py | 2 +- oauth2client/old_run.py | 160 ++++++++++++++++++++++++++++++++++++++ oauth2client/tools.py | 13 +++- 3 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 oauth2client/old_run.py diff --git a/apiclient/sample_tools.py b/apiclient/sample_tools.py index ff17b2b..ba6d754 100644 --- a/apiclient/sample_tools.py +++ b/apiclient/sample_tools.py @@ -85,7 +85,7 @@ def init(argv, name, version, doc, filename, scope=None, parents=[]): storage = file.Storage(name + '.dat') credentials = storage.get() if credentials is None or credentials.invalid: - credentials = tools.run(flow, storage, flags) + credentials = tools.run_flow(flow, storage, flags) http = credentials.authorize(http = httplib2.Http()) # Construct a service object via the discovery service. diff --git a/oauth2client/old_run.py b/oauth2client/old_run.py new file mode 100644 index 0000000..da23358 --- /dev/null +++ b/oauth2client/old_run.py @@ -0,0 +1,160 @@ +# Copyright (C) 2013 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This module holds the old run() function which is deprecated, the +tools.run_flow() function should be used in its place.""" + + +import logging +import socket +import sys +import webbrowser + +import gflags + +from oauth2client import client +from oauth2client import util +from tools import ClientRedirectHandler +from tools import ClientRedirectServer + + +FLAGS = gflags.FLAGS + +gflags.DEFINE_boolean('auth_local_webserver', True, + ('Run a local web server to handle redirects during ' + 'OAuth authorization.')) + +gflags.DEFINE_string('auth_host_name', 'localhost', + ('Host name to use when running a local web server to ' + 'handle redirects during OAuth authorization.')) + +gflags.DEFINE_multi_int('auth_host_port', [8080, 8090], + ('Port to use when running a local web server to ' + 'handle redirects during OAuth authorization.')) + + +@util.positional(2) +def run(flow, storage, http=None): + """Core code for a command-line application. + + The run() function is called from your application and runs through all + the steps to obtain credentials. It takes a Flow argument and attempts to + open an authorization server page in the user's default web browser. The + server asks the user to grant your application access to the user's data. + If the user grants access, the run() function returns new credentials. The + new credentials are also stored in the Storage argument, which updates the + file associated with the Storage object. + + It presumes it is run from a command-line application and supports the + following flags: + + --auth_host_name: Host name to use when running a local web server + to handle redirects during OAuth authorization. + (default: 'localhost') + + --auth_host_port: Port to use when running a local web server to handle + redirects during OAuth authorization.; + repeat this option to specify a list of values + (default: '[8080, 8090]') + (an integer) + + --[no]auth_local_webserver: Run a local web server to handle redirects + during OAuth authorization. + (default: 'true') + + Since it uses flags make sure to initialize the gflags module before + calling run(). + + Args: + flow: Flow, an OAuth 2.0 Flow to step through. + storage: Storage, a Storage to store the credential in. + http: An instance of httplib2.Http.request + or something that acts like it. + + Returns: + Credentials, the obtained credential. + """ + logging.warning('This function, oauth2client.tools.run(), and the use of ' + 'the gflags library are deprecated and will be removed in a future ' + 'version of the library.') + if FLAGS.auth_local_webserver: + success = False + port_number = 0 + for port in FLAGS.auth_host_port: + port_number = port + try: + httpd = ClientRedirectServer((FLAGS.auth_host_name, port), + ClientRedirectHandler) + except socket.error, e: + pass + else: + success = True + break + FLAGS.auth_local_webserver = success + if not success: + print 'Failed to start a local webserver listening on either port 8080' + print 'or port 9090. Please check your firewall settings and locally' + print 'running programs that may be blocking or using those ports.' + print + print 'Falling back to --noauth_local_webserver and continuing with', + print 'authorization.' + print + + if FLAGS.auth_local_webserver: + oauth_callback = 'http://%s:%s/' % (FLAGS.auth_host_name, port_number) + else: + oauth_callback = client.OOB_CALLBACK_URN + flow.redirect_uri = oauth_callback + authorize_url = flow.step1_get_authorize_url() + + if FLAGS.auth_local_webserver: + webbrowser.open(authorize_url, new=1, autoraise=True) + print 'Your browser has been opened to visit:' + print + print ' ' + authorize_url + print + print 'If your browser is on a different machine then exit and re-run' + print 'this application with the command-line parameter ' + print + print ' --noauth_local_webserver' + print + else: + print 'Go to the following link in your browser:' + print + print ' ' + authorize_url + print + + code = None + if FLAGS.auth_local_webserver: + httpd.handle_request() + if 'error' in httpd.query_params: + sys.exit('Authentication request was rejected.') + if 'code' in httpd.query_params: + code = httpd.query_params['code'] + else: + print 'Failed to find "code" in the query parameters of the redirect.' + sys.exit('Try running with --noauth_local_webserver.') + else: + code = raw_input('Enter verification code: ').strip() + + try: + credential = flow.step2_exchange(code, http=http) + except client.FlowExchangeError, e: + sys.exit('Authentication has failed: %s' % e) + + storage.put(credential) + credential.set_store(storage) + print 'Authentication successful.' + + return credential diff --git a/oauth2client/tools.py b/oauth2client/tools.py index e283a8a..8f01717 100644 --- a/oauth2client/tools.py +++ b/oauth2client/tools.py @@ -20,7 +20,7 @@ the same directory. """ __author__ = 'jcgregorio@google.com (Joe Gregorio)' -__all__ = ['argparser', 'run', 'message_if_missing'] +__all__ = ['argparser', 'run_flow', 'run', 'message_if_missing'] import BaseHTTPServer @@ -107,7 +107,7 @@ class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler): @util.positional(3) -def run(flow, storage, flags, http=None): +def run_flow(flow, storage, flags, http=None): """Core code for a command-line application. The run() function is called from your application and runs through all the @@ -231,3 +231,12 @@ def message_if_missing(filename): """Helpful message to display if the CLIENT_SECRETS file is missing.""" return _CLIENT_SECRETS_MESSAGE % filename + +try: + from old_run import run +except ImportError: + def run(*args, **kwargs): + raise NotImplementedError( + 'The gflags library must be installed to use tools.run(). ' + 'Please install gflags or preferrably switch to using ' + 'tools.run_flow().')