1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """Command-line tools for authenticating via OAuth 2.0
16
17 Do the OAuth 2.0 Web Server dance for a command line application. Stores the
18 generated credentials in a common file that is used by other example apps in
19 the same directory.
20 """
21
22 from __future__ import print_function
23
24 __author__ = 'jcgregorio@google.com (Joe Gregorio)'
25 __all__ = ['argparser', 'run_flow', 'run', 'message_if_missing']
26
27 import BaseHTTPServer
28 import logging
29 import socket
30 import sys
31 import webbrowser
32
33 from six.moves import urllib
34
35 from oauth2client import client
36 from oauth2client import util
37
38
39 _CLIENT_SECRETS_MESSAGE = """WARNING: Please configure OAuth 2.0
40
41 To make this sample run you will need to populate the client_secrets.json file
42 found at:
43
44 %s
45
46 with information from the APIs Console <https://code.google.com/apis/console>.
47
48 """
49
50
51
52
53 argparser = _CreateArgumentParser()
56 try:
57 import argparse
58 except ImportError:
59 return None
60 argparser = argparse.ArgumentParser(add_help=False)
61 argparser.add_argument('--auth_host_name', default='localhost',
62 help='Hostname when running a local web server.')
63 argparser.add_argument('--noauth_local_webserver', action='store_true',
64 default=False, help='Do not run a local web server.')
65 argparser.add_argument('--auth_host_port', default=[8080, 8090], type=int,
66 nargs='*', help='Port web server should listen on.')
67 argparser.add_argument('--logging_level', default='ERROR',
68 choices=['DEBUG', 'INFO', 'WARNING', 'ERROR',
69 'CRITICAL'],
70 help='Set the logging level of detail.')
71 return argparser
72
75 """A server to handle OAuth 2.0 redirects back to localhost.
76
77 Waits for a single request and parses the query parameters
78 into query_params and then stops serving.
79 """
80 query_params = {}
81
84 """A handler for OAuth 2.0 redirects back to localhost.
85
86 Waits for a single request and parses the query parameters
87 into the servers query_params and then stops serving.
88 """
89
91 """Handle a GET request.
92
93 Parses the query parameters and prints a message
94 if the flow has completed. Note that we can't detect
95 if an error occurred.
96 """
97 self.send_response(200)
98 self.send_header("Content-type", "text/html")
99 self.end_headers()
100 query = self.path.split('?', 1)[-1]
101 query = dict(urllib.parse.parse_qsl(query))
102 self.server.query_params = query
103 self.wfile.write("<html><head><title>Authentication Status</title></head>")
104 self.wfile.write("<body><p>The authentication flow has completed.</p>")
105 self.wfile.write("</body></html>")
106
108 """Do not log messages to stdout while running as command line program."""
109
113 """Core code for a command-line application.
114
115 The run() function is called from your application and runs through all the
116 steps to obtain credentials. It takes a Flow argument and attempts to open an
117 authorization server page in the user's default web browser. The server asks
118 the user to grant your application access to the user's data. If the user
119 grants access, the run() function returns new credentials. The new credentials
120 are also stored in the Storage argument, which updates the file associated
121 with the Storage object.
122
123 It presumes it is run from a command-line application and supports the
124 following flags:
125
126 --auth_host_name: Host name to use when running a local web server
127 to handle redirects during OAuth authorization.
128 (default: 'localhost')
129
130 --auth_host_port: Port to use when running a local web server to handle
131 redirects during OAuth authorization.;
132 repeat this option to specify a list of values
133 (default: '[8080, 8090]')
134 (an integer)
135
136 --[no]auth_local_webserver: Run a local web server to handle redirects
137 during OAuth authorization.
138 (default: 'true')
139
140 The tools module defines an ArgumentParser the already contains the flag
141 definitions that run() requires. You can pass that ArgumentParser to your
142 ArgumentParser constructor:
143
144 parser = argparse.ArgumentParser(description=__doc__,
145 formatter_class=argparse.RawDescriptionHelpFormatter,
146 parents=[tools.argparser])
147 flags = parser.parse_args(argv)
148
149 Args:
150 flow: Flow, an OAuth 2.0 Flow to step through.
151 storage: Storage, a Storage to store the credential in.
152 flags: argparse.ArgumentParser, the command-line flags.
153 http: An instance of httplib2.Http.request
154 or something that acts like it.
155
156 Returns:
157 Credentials, the obtained credential.
158 """
159 logging.getLogger().setLevel(getattr(logging, flags.logging_level))
160 if not flags.noauth_local_webserver:
161 success = False
162 port_number = 0
163 for port in flags.auth_host_port:
164 port_number = port
165 try:
166 httpd = ClientRedirectServer((flags.auth_host_name, port),
167 ClientRedirectHandler)
168 except socket.error:
169 pass
170 else:
171 success = True
172 break
173 flags.noauth_local_webserver = not success
174 if not success:
175 print('Failed to start a local webserver listening on either port 8080')
176 print('or port 9090. Please check your firewall settings and locally')
177 print('running programs that may be blocking or using those ports.')
178 print()
179 print('Falling back to --noauth_local_webserver and continuing with')
180 print('authorization.')
181 print()
182
183 if not flags.noauth_local_webserver:
184 oauth_callback = 'http://%s:%s/' % (flags.auth_host_name, port_number)
185 else:
186 oauth_callback = client.OOB_CALLBACK_URN
187 flow.redirect_uri = oauth_callback
188 authorize_url = flow.step1_get_authorize_url()
189
190 if not flags.noauth_local_webserver:
191 webbrowser.open(authorize_url, new=1, autoraise=True)
192 print('Your browser has been opened to visit:')
193 print()
194 print(' ' + authorize_url)
195 print()
196 print('If your browser is on a different machine then exit and re-run this')
197 print('application with the command-line parameter ')
198 print()
199 print(' --noauth_local_webserver')
200 print()
201 else:
202 print('Go to the following link in your browser:')
203 print()
204 print(' ' + authorize_url)
205 print()
206
207 code = None
208 if not flags.noauth_local_webserver:
209 httpd.handle_request()
210 if 'error' in httpd.query_params:
211 sys.exit('Authentication request was rejected.')
212 if 'code' in httpd.query_params:
213 code = httpd.query_params['code']
214 else:
215 print('Failed to find "code" in the query parameters of the redirect.')
216 sys.exit('Try running with --noauth_local_webserver.')
217 else:
218 code = raw_input('Enter verification code: ').strip()
219
220 try:
221 credential = flow.step2_exchange(code, http=http)
222 except client.FlowExchangeError as e:
223 sys.exit('Authentication has failed: %s' % e)
224
225 storage.put(credential)
226 credential.set_store(storage)
227 print('Authentication successful.')
228
229 return credential
230
236
237 try:
238 from oauth2client.old_run import run
239 from oauth2client.old_run import FLAGS
240 except ImportError:
241 - def run(*args, **kwargs):
242 raise NotImplementedError(
243 'The gflags library must be installed to use tools.run(). '
244 'Please install gflags or preferrably switch to using '
245 'tools.run_flow().')
246