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