1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
|
"""
Authentication capabilities for the Flickr API.
It implements the new authentication specifications of Flickr
based on OAuth.
The authentication process is in 3 steps.
- Authorisation request:
>>> a = AuthHandler(call_back_url)
>>> a.get_authorization_url('write')
print ('http://www.flickr.com/services/oauth/'
'authorize?oauth_token=xxxx&perms=write')
- The user gives his authorization at the url given by
'get_authorization_url' and is redirected to the 'call_back_url' with
the `oauth_verifier` encoded in the url. This value can then be given to
the `AuthHandler`:
>>> a.set_verifier("66455xxxxx")
- The authorization handler can then be set for the python session
and will be automatically used when needed.
>>> flickr_api.set_auth_handler(a)
The authorization handler can also be saved and loaded:
>>> a.write(filename)
>>> a = AuthHandler.load(filename)
Date: 06/08/2011
Author: Alexis Mignon <alexis.mignon@gmail.com>
Author: Christoffer Viken <christoffer@viken.me>
"""
try: # fixes a reported bug. Seems that oauth can be packed in different ways.
from oauth import oauth
except ImportError:
import oauth
import time
import urllib.parse
import urllib.request, urllib.error, urllib.parse
from . import keys
TOKEN_REQUEST_URL = "https://www.flickr.com/services/oauth/request_token"
AUTHORIZE_URL = "https://www.flickr.com/services/oauth/authorize"
ACCESS_TOKEN_URL = "https://www.flickr.com/services/oauth/access_token"
AUTH_HANDLER = None
class AuthHandlerError(Exception):
pass
class AuthHandler(object):
def __init__(self, key=None, secret=None, callback=None,
access_token_key=None, access_token_secret=None,
request_token_key=None, request_token_secret=None):
self.key = key or keys.API_KEY
self.secret = secret or keys.API_SECRET
if self.key is None or self.secret is None:
raise ValueError("API keys have not been set.")
if callback is None:
callback = ("https://api.flickr.com/services/rest/"
"?method=flickr.test.echo&api_key=%s" % self.key)
params = {
'oauth_timestamp': str(int(time.time())),
'oauth_signature_method': "HMAC-SHA1",
'oauth_version': "1.0",
'oauth_callback': callback,
'oauth_nonce': oauth.generate_nonce(),
'oauth_consumer_key': self.key
}
self.consumer = oauth.OAuthConsumer(key=self.key, secret=self.secret)
if (access_token_key is None) and (request_token_key is None):
req = oauth.OAuthRequest(http_method="GET",
http_url=TOKEN_REQUEST_URL,
parameters=params)
req.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(),
self.consumer, None)
resp = urllib.request.urlopen(req.to_url())
request_token = dict(urllib.parse.parse_qsl(resp.read()))
self.request_token = oauth.OAuthToken(
request_token['oauth_token'],
request_token['oauth_token_secret']
)
self.access_token = None
elif request_token_key is not None:
self.access_token = None
self.request_token = oauth.OAuthToken(
request_token_key,
request_token_secret
)
else:
self.request_token = None
self.access_token = oauth.OAuthToken(
access_token_key,
access_token_secret
)
def get_authorization_url(self, perms='read'):
if self.request_token is None:
raise AuthHandlerError(
("Request token is not defined. This ususally means that the"
" access token has been loaded from a file.")
)
return "%s?oauth_token=%s&perms=%s" % (
AUTHORIZE_URL, self.request_token.key, perms
)
def set_verifier(self, oauth_verifier):
if self.request_token is None:
raise AuthHandlerError(
("Request token is not defined. "
"This ususally means that the access token has been loaded "
"from a file.")
)
self.request_token.set_verifier(oauth_verifier)
access_token_parms = {
'oauth_consumer_key': self.key,
'oauth_nonce': oauth.generate_nonce(),
'oauth_signature_method': "HMAC-SHA1",
'oauth_timestamp': str(int(time.time())),
'oauth_token': self.request_token.key,
'oauth_verifier': self.request_token.verifier
}
req = oauth.OAuthRequest(http_method="GET", http_url=ACCESS_TOKEN_URL,
parameters=access_token_parms)
req.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(),
self.consumer, self.request_token)
resp = urllib.request.urlopen(req.to_url())
access_token_resp = dict(urllib.parse.parse_qsl(resp.read()))
self.access_token = oauth.OAuthToken(
access_token_resp["oauth_token"],
access_token_resp["oauth_token_secret"]
)
def complete_parameters(self, url, params={}, exclude_signature=[]):
defaults = {
'oauth_timestamp': str(int(time.time())),
'oauth_nonce': oauth.generate_nonce(),
'signature_method': "HMAC-SHA1",
'oauth_token': self.access_token.key,
'oauth_consumer_key': self.consumer.key,
}
excluded = {}
for e in exclude_signature:
excluded[e] = params.pop(e)
defaults.update(params)
req = oauth.OAuthRequest(http_method="POST", http_url=url,
parameters=defaults)
req.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), self.consumer,
self.access_token)
req.parameters.update(excluded)
return req
def tofile(self, filename, include_api_keys=False):
""" saves authentication information to a file.
Parameters:
----------
filename: str
The name of the file to which we save the information.
include_api_keys: bool, optional (default False)
Should we include the api keys in the file ? For security issues, it
is recommanded not to save the API keys information in several places
and the default behaviour is thus not to save the API keys.
"""
if self.access_token is None:
raise AuthHandlerError("Access token not set yet.")
with open(filename, "w") as f:
if include_api_keys:
f.write("\n".join([self.key, self.secret,
self.access_token.key, self.access_token.secret]))
else:
f.write("\n".join([self.access_token.key,
self.access_token.secret]))
def save(self, filename, include_api_keys=False):
self.tofile(filename, include_api_keys)
def write(self, filename, include_api_keys=False):
self.tofile(filename, include_api_keys)
def todict(self, include_api_keys=False):
"""
Dumps the auth object to a dict,
Optional inclusion of API-keys, in case you are using multiple.
- include_api_keys: Whether API-keys should be included, False if you
have control of them.
"""
if self.access_token is not None:
dump = {'access_token_key': self.access_token.key,
'access_token_secret': self.access_token.secret}
else:
dump = {'request_token_key': self.request_token.key,
'request_token_secret': self.request_token.secret}
if include_api_keys:
dump['api_key'] = self.key
dump['api_secret'] = self.secret
return dump
@staticmethod
def load(filename, set_api_keys=False):
""" Load authentication information from a file.
Parameters
----------
filename: str
The file in which authentication information is stored.
set_api_keys: bool, optional (default False)
If API keys are found in the file, should we use them to set the
API keys globally.
Default is False. The API keys should be stored separately from
authentication information. The recommanded way is to use a
`flickr_keys.py` file. Setting `set_api_keys=True` should be considered
as a conveniency only for single user settings.
"""
return AuthHandler.fromfile(filename, set_api_keys)
@staticmethod
def fromfile(filename, set_api_keys=False):
""" Load authentication information from a file.
Parameters
----------
filename: str
The file in which authentication information is stored.
set_api_keys: bool, optional (default False)
If API keys are found in the file, should we use them to set the
API keys globally.
Default is False. The API keys should be stored separately from
authentication information. The recommanded way is to use a
`flickr_keys.py` file. Setting `set_api_keys=True` should be considered
as a conveniency only for single user settings.
"""
with open(filename, "r") as f:
keys_info = f.read().split("\n")
try:
key, secret, access_key, access_secret = keys_info
if set_api_keys:
keys.set_keys(api_key=key, api_secret=secret)
except ValueError:
access_key, access_secret = keys_info
key = keys.API_KEY
secret = keys.API_SECRET
return AuthHandler(key, secret, access_token_key=access_key,
access_token_secret=access_secret)
@staticmethod
def fromdict(input_dict):
"""
Loads an auth object from a dict.
Structure identical to dict returned by todict
- input_dict: Dictionary to build from
"""
access_key, access_secret = None, None
request_token_key, request_token_secret = None, None
try:
if 'api_key' in input_dict:
key = input_dict['api_key']
secret = input_dict['api_secret']
else:
key = keys.API_KEY
secret = keys.API_SECRET
if 'access_token_key' in input_dict:
access_key = input_dict['access_token_key']
access_secret = input_dict['access_token_secret']
elif 'request_token_key' in input_dict:
request_token_key = input_dict['request_token_key']
request_token_secret = input_dict['request_token_secret']
except Exception:
raise AuthHandlerError("Error occurred while processing data")
return AuthHandler(key, secret, access_token_key=access_key,
access_token_secret=access_secret,
request_token_key=request_token_key,
request_token_secret=request_token_secret)
@staticmethod
def create(access_key, access_secret):
return AuthHandler(access_token_key=access_key,
access_token_secret=access_secret)
def token_factory(filename=None, token_key=None, token_secret=None):
if filename is None:
if (token_key is None) or (token_secret is None):
raise ValueError("token_secret and token_key cannot be None")
return AuthHandler.create(token_key, token_secret)
else:
return AuthHandler.load(filename)
def set_auth_handler(auth_handler, set_api_keys=False):
""" Set the authentication handler globally.
Parameters
----------
auth_handler: AuthHandler object or str
If a string is given, it corresponds to the file in which
authentication information is stored.
set_api_keys: bool, optional (default False)
If API keys are found in the file, should we use them to set the
API keys globally.
Default is False. The API keys should be stored separately from
authentication information. The recommanded way is to use a
`flickr_keys.py` file. Setting `set_api_keys=True` should be considered
as a conveniency only for single user settings.
"""
global AUTH_HANDLER
if isinstance(auth_handler, str):
ah = AuthHandler.load(auth_handler, set_api_keys)
set_auth_handler(ah)
else:
AUTH_HANDLER = auth_handler
|