blob: 57f639004ace155fd2f608c2c22a43c07b630e60 [file] [log] [blame]
Joe Gregorio695fdc12011-01-16 16:46:55 -05001# Copyright (C) 2010 Google Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Command-line tools for authenticating via OAuth 2.0
16
17Do the OAuth 2.0 Web Server dance for
18a command line application. Stores the generated
19credentials in a common file that is used by
20other example apps in the same directory.
21"""
22
23__author__ = 'jcgregorio@google.com (Joe Gregorio)'
24__all__ = ["run"]
25
26import socket
27import sys
28import BaseHTTPServer
29import logging
30
31from optparse import OptionParser
32from oauth2client.file import Storage
33
34try:
35 from urlparse import parse_qsl
36except ImportError:
37 from cgi import parse_qsl
38
39# TODO(jcgregorio)
40# - docs
41# - error handling
42# - oob when implemented
43
44
45class ClientRedirectServer(BaseHTTPServer.HTTPServer):
46 """A server to handle OAuth 2.0 redirects back to localhost.
47
48 Waits for a single request and parses the query parameters
49 into query_params and then stops serving.
50 """
51 query_params = {}
52
53class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler):
54 """A handler for OAuth 2.0 redirects back to localhost.
55
56 Waits for a single request and parses the query parameters
57 into the servers query_params and then stops serving.
58 """
59
60 def do_GET(s):
61 """Handle a GET request
62
63 Checks the query parameters and if an error
64 occurred print a message of failure, otherwise
65 indicate success.
66 """
67 s.send_response(200)
68 s.send_header("Content-type", "text/html")
69 s.end_headers()
70 query = s.path.split('?', 1)[-1]
71 query = dict(parse_qsl(query))
72 s.server.query_params = query
73 s.wfile.write("<html><head><title>Authentication Status</title></head>")
74 if 'error' in query:
75 s.wfile.write("<body><p>The authentication request failed.</p>")
76 else:
77 s.wfile.write("<body><p>You have successfully authenticated</p>")
78 s.wfile.write("</body></html>")
79
80 def log_message(self, format, *args):
81 """Do not log messages to stdout while running as a command line program."""
82 pass
83
84def run(flow, filename):
85 """Core code for a command-line application.
86 """
87 parser = OptionParser()
88 parser.add_option("-f", "--file", dest="filename",
89 default=filename, help="write credentials to FILE", metavar="FILE")
90 parser.add_option("-p", "--no_local_web_server", dest="localhost",
91 action="store_false",
92 default=True,
93 help="Do not run a web server on localhost to handle redirect URIs")
94 parser.add_option("-w", "--local_web_server", dest="localhost",
95 action="store_true",
96 default=True,
97 help="Run a web server on localhost to handle redirect URIs")
98
99 (options, args) = parser.parse_args()
100
101 host_name = 'localhost'
102 port_numbers = [8080, 8090]
103 if options.localhost:
104 server_class = BaseHTTPServer.HTTPServer
105 try:
106 port_number = port_numbers[0]
107 httpd = server_class((host_name, port_number), ClientRedirectHandler)
108 except socket.error:
109 port_number = port_numbers[1]
110 try:
111 httpd = server_class((host_name, port_number), ClientRedirectHandler)
112 except socket.error:
113 options.localhost = False
114
115 authorize_url = flow.step1_get_authorize_url('http://%s:%s/' % (host_name, port_number))
116
117 print 'Go to the following link in your browser:'
118 print authorize_url
119 print
120
121 if options.localhost:
122 httpd.handle_request()
123 if 'error' in httpd.query_params:
124 sys.exit('Authentication request was rejected.')
125 if 'code' in httpd.query_params:
126 code = httpd.query_params['code']
127 else:
128 accepted = 'n'
129 while accepted.lower() == 'n':
130 accepted = raw_input('Have you authorized me? (y/n) ')
131 code = raw_input('What is the verification code? ').strip()
132
133 credentials = flow.step2_exchange(code)
134
135 Storage(options.filename).put(credentials)
136 print "You have successfully authenticated."