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__ = ['run']
24
25
26 import BaseHTTPServer
27 import gflags
28 import socket
29 import sys
30 import webbrowser
31
32 from oauth2client.client import FlowExchangeError
33 from oauth2client.client import OOB_CALLBACK_URN
34 from oauth2client import util
35
36 try:
37 from urlparse import parse_qsl
38 except ImportError:
39 from cgi import parse_qsl
40
41
42 FLAGS = gflags.FLAGS
43
44 gflags.DEFINE_boolean('auth_local_webserver', True,
45 ('Run a local web server to handle redirects during '
46 'OAuth authorization.'))
47
48 gflags.DEFINE_string('auth_host_name', 'localhost',
49 ('Host name to use when running a local web server to '
50 'handle redirects during OAuth authorization.'))
51
52 gflags.DEFINE_multi_int('auth_host_port', [8080, 8090],
53 ('Port to use when running a local web server to '
54 'handle redirects during OAuth authorization.'))
58 """A server to handle OAuth 2.0 redirects back to localhost.
59
60 Waits for a single request and parses the query parameters
61 into query_params and then stops serving.
62 """
63 query_params = {}
64
67 """A handler for OAuth 2.0 redirects back to localhost.
68
69 Waits for a single request and parses the query parameters
70 into the servers query_params and then stops serving.
71 """
72
74 """Handle a GET request.
75
76 Parses the query parameters and prints a message
77 if the flow has completed. Note that we can't detect
78 if an error occurred.
79 """
80 s.send_response(200)
81 s.send_header("Content-type", "text/html")
82 s.end_headers()
83 query = s.path.split('?', 1)[-1]
84 query = dict(parse_qsl(query))
85 s.server.query_params = query
86 s.wfile.write("<html><head><title>Authentication Status</title></head>")
87 s.wfile.write("<body><p>The authentication flow has completed.</p>")
88 s.wfile.write("</body></html>")
89
91 """Do not log messages to stdout while running as command line program."""
92 pass
93
97 """Core code for a command-line application.
98
99 Args:
100 flow: Flow, an OAuth 2.0 Flow to step through.
101 storage: Storage, a Storage to store the credential in.
102 http: An instance of httplib2.Http.request
103 or something that acts like it.
104
105 Returns:
106 Credentials, the obtained credential.
107 """
108 if FLAGS.auth_local_webserver:
109 success = False
110 port_number = 0
111 for port in FLAGS.auth_host_port:
112 port_number = port
113 try:
114 httpd = ClientRedirectServer((FLAGS.auth_host_name, port),
115 ClientRedirectHandler)
116 except socket.error, e:
117 pass
118 else:
119 success = True
120 break
121 FLAGS.auth_local_webserver = success
122 if not success:
123 print 'Failed to start a local webserver listening on either port 8080'
124 print 'or port 9090. Please check your firewall settings and locally'
125 print 'running programs that may be blocking or using those ports.'
126 print
127 print 'Falling back to --noauth_local_webserver and continuing with',
128 print 'authorization.'
129 print
130
131 if FLAGS.auth_local_webserver:
132 oauth_callback = 'http://%s:%s/' % (FLAGS.auth_host_name, port_number)
133 else:
134 oauth_callback = OOB_CALLBACK_URN
135 flow.redirect_uri = oauth_callback
136 authorize_url = flow.step1_get_authorize_url()
137
138 if FLAGS.auth_local_webserver:
139 webbrowser.open(authorize_url, new=1, autoraise=True)
140 print 'Your browser has been opened to visit:'
141 print
142 print ' ' + authorize_url
143 print
144 print 'If your browser is on a different machine then exit and re-run this'
145 print 'application with the command-line parameter '
146 print
147 print ' --noauth_local_webserver'
148 print
149 else:
150 print 'Go to the following link in your browser:'
151 print
152 print ' ' + authorize_url
153 print
154
155 code = None
156 if FLAGS.auth_local_webserver:
157 httpd.handle_request()
158 if 'error' in httpd.query_params:
159 sys.exit('Authentication request was rejected.')
160 if 'code' in httpd.query_params:
161 code = httpd.query_params['code']
162 else:
163 print 'Failed to find "code" in the query parameters of the redirect.'
164 sys.exit('Try running with --noauth_local_webserver.')
165 else:
166 code = raw_input('Enter verification code: ').strip()
167
168 try:
169 credential = flow.step2_exchange(code, http=http)
170 except FlowExchangeError, e:
171 sys.exit('Authentication has failed: %s' % e)
172
173 storage.put(credential)
174 credential.set_store(storage)
175 print 'Authentication successful.'
176
177 return credential
178