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