p@21
|
1 """
|
p@21
|
2 The MIT License
|
p@21
|
3
|
p@21
|
4 Copyright (c) 2007 Leah Culver
|
p@21
|
5
|
p@21
|
6 Permission is hereby granted, free of charge, to any person obtaining a copy
|
p@21
|
7 of this software and associated documentation files (the "Software"), to deal
|
p@21
|
8 in the Software without restriction, including without limitation the rights
|
p@21
|
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
p@21
|
10 copies of the Software, and to permit persons to whom the Software is
|
p@21
|
11 furnished to do so, subject to the following conditions:
|
p@21
|
12
|
p@21
|
13 The above copyright notice and this permission notice shall be included in
|
p@21
|
14 all copies or substantial portions of the Software.
|
p@21
|
15
|
p@21
|
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
p@21
|
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
p@21
|
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
p@21
|
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
p@21
|
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
p@21
|
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
p@21
|
22 THE SOFTWARE.
|
p@21
|
23 """
|
p@21
|
24
|
p@21
|
25 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
p@21
|
26 import urllib
|
p@21
|
27
|
p@21
|
28 import oauth.oauth as oauth
|
p@21
|
29
|
p@21
|
30 # fake urls for the test server
|
p@21
|
31 REQUEST_TOKEN_URL = 'https://photos.example.net/request_token'
|
p@21
|
32 ACCESS_TOKEN_URL = 'https://photos.example.net/access_token'
|
p@21
|
33 AUTHORIZATION_URL = 'https://photos.example.net/authorize'
|
p@21
|
34 CALLBACK_URL = 'http://printer.example.com/request_token_ready'
|
p@21
|
35 RESOURCE_URL = 'http://photos.example.net/photos'
|
p@21
|
36 REALM = 'http://photos.example.net/'
|
p@21
|
37 VERIFIER = 'verifier'
|
p@21
|
38
|
p@21
|
39 # example store for one of each thing
|
p@21
|
40 class MockOAuthDataStore(oauth.OAuthDataStore):
|
p@21
|
41
|
p@21
|
42 def __init__(self):
|
p@21
|
43 self.consumer = oauth.OAuthConsumer('key', 'secret')
|
p@21
|
44 self.request_token = oauth.OAuthToken('requestkey', 'requestsecret')
|
p@21
|
45 self.access_token = oauth.OAuthToken('accesskey', 'accesssecret')
|
p@21
|
46 self.nonce = 'nonce'
|
p@21
|
47 self.verifier = VERIFIER
|
p@21
|
48
|
p@21
|
49 def lookup_consumer(self, key):
|
p@21
|
50 if key == self.consumer.key:
|
p@21
|
51 return self.consumer
|
p@21
|
52 return None
|
p@21
|
53
|
p@21
|
54 def lookup_token(self, token_type, token):
|
p@21
|
55 token_attrib = getattr(self, '%s_token' % token_type)
|
p@21
|
56 if token == token_attrib.key:
|
p@21
|
57 ## HACK
|
p@21
|
58 token_attrib.set_callback(CALLBACK_URL)
|
p@21
|
59 return token_attrib
|
p@21
|
60 return None
|
p@21
|
61
|
p@21
|
62 def lookup_nonce(self, oauth_consumer, oauth_token, nonce):
|
p@21
|
63 if oauth_token and oauth_consumer.key == self.consumer.key and (oauth_token.key == self.request_token.key or oauth_token.key == self.access_token.key) and nonce == self.nonce:
|
p@21
|
64 return self.nonce
|
p@21
|
65 return None
|
p@21
|
66
|
p@21
|
67 def fetch_request_token(self, oauth_consumer, oauth_callback):
|
p@21
|
68 if oauth_consumer.key == self.consumer.key:
|
p@21
|
69 if oauth_callback:
|
p@21
|
70 # want to check here if callback is sensible
|
p@21
|
71 # for mock store, we assume it is
|
p@21
|
72 self.request_token.set_callback(oauth_callback)
|
p@21
|
73 return self.request_token
|
p@21
|
74 return None
|
p@21
|
75
|
p@21
|
76 def fetch_access_token(self, oauth_consumer, oauth_token, oauth_verifier):
|
p@21
|
77 if oauth_consumer.key == self.consumer.key and oauth_token.key == self.request_token.key and oauth_verifier == self.verifier:
|
p@21
|
78 # want to check here if token is authorized
|
p@21
|
79 # for mock store, we assume it is
|
p@21
|
80 return self.access_token
|
p@21
|
81 return None
|
p@21
|
82
|
p@21
|
83 def authorize_request_token(self, oauth_token, user):
|
p@21
|
84 if oauth_token.key == self.request_token.key:
|
p@21
|
85 # authorize the request token in the store
|
p@21
|
86 # for mock store, do nothing
|
p@21
|
87 return self.request_token
|
p@21
|
88 return None
|
p@21
|
89
|
p@21
|
90 class RequestHandler(BaseHTTPRequestHandler):
|
p@21
|
91
|
p@21
|
92 def __init__(self, *args, **kwargs):
|
p@21
|
93 self.oauth_server = oauth.OAuthServer(MockOAuthDataStore())
|
p@21
|
94 self.oauth_server.add_signature_method(oauth.OAuthSignatureMethod_PLAINTEXT())
|
p@21
|
95 self.oauth_server.add_signature_method(oauth.OAuthSignatureMethod_HMAC_SHA1())
|
p@21
|
96 BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
|
p@21
|
97
|
p@21
|
98 # example way to send an oauth error
|
p@21
|
99 def send_oauth_error(self, err=None):
|
p@21
|
100 # send a 401 error
|
p@21
|
101 self.send_error(401, str(err.message))
|
p@21
|
102 # return the authenticate header
|
p@21
|
103 header = oauth.build_authenticate_header(realm=REALM)
|
p@21
|
104 for k, v in header.iteritems():
|
p@21
|
105 self.send_header(k, v)
|
p@21
|
106
|
p@21
|
107 def do_GET(self):
|
p@21
|
108
|
p@21
|
109 # debug info
|
p@21
|
110 #print self.command, self.path, self.headers
|
p@21
|
111
|
p@21
|
112 # get the post data (if any)
|
p@21
|
113 postdata = None
|
p@21
|
114 if self.command == 'POST':
|
p@21
|
115 try:
|
p@21
|
116 length = int(self.headers.getheader('content-length'))
|
p@21
|
117 postdata = self.rfile.read(length)
|
p@21
|
118 except:
|
p@21
|
119 pass
|
p@21
|
120
|
p@21
|
121 # construct the oauth request from the request parameters
|
p@21
|
122 oauth_request = oauth.OAuthRequest.from_request(self.command, self.path, headers=self.headers, query_string=postdata)
|
p@21
|
123
|
p@21
|
124 # request token
|
p@21
|
125 if self.path.startswith(REQUEST_TOKEN_URL):
|
p@21
|
126 try:
|
p@21
|
127 # create a request token
|
p@21
|
128 token = self.oauth_server.fetch_request_token(oauth_request)
|
p@21
|
129 # send okay response
|
p@21
|
130 self.send_response(200, 'OK')
|
p@21
|
131 self.end_headers()
|
p@21
|
132 # return the token
|
p@21
|
133 self.wfile.write(token.to_string())
|
p@21
|
134 except oauth.OAuthError, err:
|
p@21
|
135 self.send_oauth_error(err)
|
p@21
|
136 return
|
p@21
|
137
|
p@21
|
138 # user authorization
|
p@21
|
139 if self.path.startswith(AUTHORIZATION_URL):
|
p@21
|
140 try:
|
p@21
|
141 # get the request token
|
p@21
|
142 token = self.oauth_server.fetch_request_token(oauth_request)
|
p@21
|
143 # authorize the token (kind of does nothing for now)
|
p@21
|
144 token = self.oauth_server.authorize_token(token, None)
|
p@21
|
145 token.set_verifier(VERIFIER)
|
p@21
|
146 # send okay response
|
p@21
|
147 self.send_response(200, 'OK')
|
p@21
|
148 self.end_headers()
|
p@21
|
149 # return the callback url (to show server has it)
|
p@21
|
150 self.wfile.write(token.get_callback_url())
|
p@21
|
151 except oauth.OAuthError, err:
|
p@21
|
152 self.send_oauth_error(err)
|
p@21
|
153 return
|
p@21
|
154
|
p@21
|
155 # access token
|
p@21
|
156 if self.path.startswith(ACCESS_TOKEN_URL):
|
p@21
|
157 try:
|
p@21
|
158 # create an access token
|
p@21
|
159 token = self.oauth_server.fetch_access_token(oauth_request)
|
p@21
|
160 # send okay response
|
p@21
|
161 self.send_response(200, 'OK')
|
p@21
|
162 self.end_headers()
|
p@21
|
163 # return the token
|
p@21
|
164 self.wfile.write(token.to_string())
|
p@21
|
165 except oauth.OAuthError, err:
|
p@21
|
166 self.send_oauth_error(err)
|
p@21
|
167 return
|
p@21
|
168
|
p@21
|
169 # protected resources
|
p@21
|
170 if self.path.startswith(RESOURCE_URL):
|
p@21
|
171 try:
|
p@21
|
172 # verify the request has been oauth authorized
|
p@21
|
173 consumer, token, params = self.oauth_server.verify_request(oauth_request)
|
p@21
|
174 # send okay response
|
p@21
|
175 self.send_response(200, 'OK')
|
p@21
|
176 self.end_headers()
|
p@21
|
177 # return the extra parameters - just for something to return
|
p@21
|
178 self.wfile.write(str(params))
|
p@21
|
179 except oauth.OAuthError, err:
|
p@21
|
180 self.send_oauth_error(err)
|
p@21
|
181 return
|
p@21
|
182
|
p@21
|
183 def do_POST(self):
|
p@21
|
184 return self.do_GET()
|
p@21
|
185
|
p@21
|
186 def main():
|
p@21
|
187 try:
|
p@21
|
188 server = HTTPServer(('', 8080), RequestHandler)
|
p@21
|
189 print 'Test server running...'
|
p@21
|
190 server.serve_forever()
|
p@21
|
191 except KeyboardInterrupt:
|
p@21
|
192 server.socket.close()
|
p@21
|
193
|
p@21
|
194 if __name__ == '__main__':
|
p@21
|
195 main() |