~parinporecha/gtg/global_shortcut

« back to all changes in this revision

Viewing changes to GTG/backends/tweepy/oauth.py

  • Committer: Izidor Matušov
  • Date: 2013-01-10 15:03:42 UTC
  • Revision ID: izidor.matusov@gmail.com-20130110150342-ajwnwmc2trh9ia2v
Removing broken twitter and tweepy services

I don't know anybody uses them. They are broken, and pretty artificial (more proof of the concept). We should focus our efforts on normal synchronization.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""
2
 
The MIT License
3
 
 
4
 
Copyright (c) 2007 Leah Culver
5
 
 
6
 
Permission is hereby granted, free of charge, to any person obtaining a copy
7
 
of this software and associated documentation files (the "Software"), to deal
8
 
in the Software without restriction, including without limitation the rights
9
 
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 
copies of the Software, and to permit persons to whom the Software is
11
 
furnished to do so, subject to the following conditions:
12
 
 
13
 
The above copyright notice and this permission notice shall be included in
14
 
all copies or substantial portions of the Software.
15
 
 
16
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 
THE SOFTWARE.
23
 
"""
24
 
 
25
 
import cgi
26
 
import urllib
27
 
import time
28
 
import random
29
 
import urlparse
30
 
import hmac
31
 
import binascii
32
 
 
33
 
 
34
 
VERSION = '1.0' # Hi Blaine!
35
 
HTTP_METHOD = 'GET'
36
 
SIGNATURE_METHOD = 'PLAINTEXT'
37
 
 
38
 
 
39
 
class OAuthError(RuntimeError):
40
 
    """Generic exception class."""
41
 
    def __init__(self, message='OAuth error occured.'):
42
 
        self.message = message
43
 
 
44
 
def build_authenticate_header(realm=''):
45
 
    """Optional WWW-Authenticate header (401 error)"""
46
 
    return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
47
 
 
48
 
def escape(s):
49
 
    """Escape a URL including any /."""
50
 
    return urllib.quote(s, safe='~')
51
 
 
52
 
def _utf8_str(s):
53
 
    """Convert unicode to utf-8."""
54
 
    if isinstance(s, unicode):
55
 
        return s.encode("utf-8")
56
 
    else:
57
 
        return str(s)
58
 
 
59
 
def generate_timestamp():
60
 
    """Get seconds since epoch (UTC)."""
61
 
    return int(time.time())
62
 
 
63
 
def generate_nonce(length=8):
64
 
    """Generate pseudorandom number."""
65
 
    return ''.join([str(random.randint(0, 9)) for i in range(length)])
66
 
 
67
 
def generate_verifier(length=8):
68
 
    """Generate pseudorandom number."""
69
 
    return ''.join([str(random.randint(0, 9)) for i in range(length)])
70
 
 
71
 
 
72
 
class OAuthConsumer(object):
73
 
    """Consumer of OAuth authentication.
74
 
 
75
 
    OAuthConsumer is a data type that represents the identity of the Consumer
76
 
    via its shared secret with the Service Provider.
77
 
 
78
 
    """
79
 
    key = None
80
 
    secret = None
81
 
 
82
 
    def __init__(self, key, secret):
83
 
        self.key = key
84
 
        self.secret = secret
85
 
 
86
 
 
87
 
class OAuthToken(object):
88
 
    """OAuthToken is a data type that represents an End User via either an access
89
 
    or request token.
90
 
    
91
 
    key -- the token
92
 
    secret -- the token secret
93
 
 
94
 
    """
95
 
    key = None
96
 
    secret = None
97
 
    callback = None
98
 
    callback_confirmed = None
99
 
    verifier = None
100
 
 
101
 
    def __init__(self, key, secret):
102
 
        self.key = key
103
 
        self.secret = secret
104
 
 
105
 
    def set_callback(self, callback):
106
 
        self.callback = callback
107
 
        self.callback_confirmed = 'true'
108
 
 
109
 
    def set_verifier(self, verifier=None):
110
 
        if verifier is not None:
111
 
            self.verifier = verifier
112
 
        else:
113
 
            self.verifier = generate_verifier()
114
 
 
115
 
    def get_callback_url(self):
116
 
        if self.callback and self.verifier:
117
 
            # Append the oauth_verifier.
118
 
            parts = urlparse.urlparse(self.callback)
119
 
            scheme, netloc, path, params, query, fragment = parts[:6]
120
 
            if query:
121
 
                query = '%s&oauth_verifier=%s' % (query, self.verifier)
122
 
            else:
123
 
                query = 'oauth_verifier=%s' % self.verifier
124
 
            return urlparse.urlunparse((scheme, netloc, path, params,
125
 
                query, fragment))
126
 
        return self.callback
127
 
 
128
 
    def to_string(self):
129
 
        data = {
130
 
            'oauth_token': self.key,
131
 
            'oauth_token_secret': self.secret,
132
 
        }
133
 
        if self.callback_confirmed is not None:
134
 
            data['oauth_callback_confirmed'] = self.callback_confirmed
135
 
        return urllib.urlencode(data)
136
 
 
137
 
    def from_string(s):
138
 
        """ Returns a token from something like:
139
 
        oauth_token_secret=xxx&oauth_token=xxx
140
 
        """
141
 
        params = cgi.parse_qs(s, keep_blank_values=False)
142
 
        key = params['oauth_token'][0]
143
 
        secret = params['oauth_token_secret'][0]
144
 
        token = OAuthToken(key, secret)
145
 
        try:
146
 
            token.callback_confirmed = params['oauth_callback_confirmed'][0]
147
 
        except KeyError:
148
 
            pass # 1.0, no callback confirmed.
149
 
        return token
150
 
    from_string = staticmethod(from_string)
151
 
 
152
 
    def __str__(self):
153
 
        return self.to_string()
154
 
 
155
 
 
156
 
class OAuthRequest(object):
157
 
    """OAuthRequest represents the request and can be serialized.
158
 
 
159
 
    OAuth parameters:
160
 
        - oauth_consumer_key 
161
 
        - oauth_token
162
 
        - oauth_signature_method
163
 
        - oauth_signature 
164
 
        - oauth_timestamp 
165
 
        - oauth_nonce
166
 
        - oauth_version
167
 
        - oauth_verifier
168
 
        ... any additional parameters, as defined by the Service Provider.
169
 
    """
170
 
    parameters = None # OAuth parameters.
171
 
    http_method = HTTP_METHOD
172
 
    http_url = None
173
 
    version = VERSION
174
 
 
175
 
    def __init__(self, http_method=HTTP_METHOD, http_url=None, parameters=None):
176
 
        self.http_method = http_method
177
 
        self.http_url = http_url
178
 
        self.parameters = parameters or {}
179
 
 
180
 
    def set_parameter(self, parameter, value):
181
 
        self.parameters[parameter] = value
182
 
 
183
 
    def get_parameter(self, parameter):
184
 
        try:
185
 
            return self.parameters[parameter]
186
 
        except:
187
 
            raise OAuthError('Parameter not found: %s' % parameter)
188
 
 
189
 
    def _get_timestamp_nonce(self):
190
 
        return self.get_parameter('oauth_timestamp'), self.get_parameter(
191
 
            'oauth_nonce')
192
 
 
193
 
    def get_nonoauth_parameters(self):
194
 
        """Get any non-OAuth parameters."""
195
 
        parameters = {}
196
 
        for k, v in self.parameters.iteritems():
197
 
            # Ignore oauth parameters.
198
 
            if k.find('oauth_') < 0:
199
 
                parameters[k] = v
200
 
        return parameters
201
 
 
202
 
    def to_header(self, realm=''):
203
 
        """Serialize as a header for an HTTPAuth request."""
204
 
        auth_header = 'OAuth realm="%s"' % realm
205
 
        # Add the oauth parameters.
206
 
        if self.parameters:
207
 
            for k, v in self.parameters.iteritems():
208
 
                if k[:6] == 'oauth_':
209
 
                    auth_header += ', %s="%s"' % (k, escape(str(v)))
210
 
        return {'Authorization': auth_header}
211
 
 
212
 
    def to_postdata(self):
213
 
        """Serialize as post data for a POST request."""
214
 
        return '&'.join(['%s=%s' % (escape(str(k)), escape(str(v))) \
215
 
            for k, v in self.parameters.iteritems()])
216
 
 
217
 
    def to_url(self):
218
 
        """Serialize as a URL for a GET request."""
219
 
        return '%s?%s' % (self.get_normalized_http_url(), self.to_postdata())
220
 
 
221
 
    def get_normalized_parameters(self):
222
 
        """Return a string that contains the parameters that must be signed."""
223
 
        params = self.parameters
224
 
        try:
225
 
            # Exclude the signature if it exists.
226
 
            del params['oauth_signature']
227
 
        except:
228
 
            pass
229
 
        # Escape key values before sorting.
230
 
        key_values = [(escape(_utf8_str(k)), escape(_utf8_str(v))) \
231
 
            for k,v in params.items()]
232
 
        # Sort lexicographically, first after key, then after value.
233
 
        key_values.sort()
234
 
        # Combine key value pairs into a string.
235
 
        return '&'.join(['%s=%s' % (k, v) for k, v in key_values])
236
 
 
237
 
    def get_normalized_http_method(self):
238
 
        """Uppercases the http method."""
239
 
        return self.http_method.upper()
240
 
 
241
 
    def get_normalized_http_url(self):
242
 
        """Parses the URL and rebuilds it to be scheme://host/path."""
243
 
        parts = urlparse.urlparse(self.http_url)
244
 
        scheme, netloc, path = parts[:3]
245
 
        # Exclude default port numbers.
246
 
        if scheme == 'http' and netloc[-3:] == ':80':
247
 
            netloc = netloc[:-3]
248
 
        elif scheme == 'https' and netloc[-4:] == ':443':
249
 
            netloc = netloc[:-4]
250
 
        return '%s://%s%s' % (scheme, netloc, path)
251
 
 
252
 
    def sign_request(self, signature_method, consumer, token):
253
 
        """Set the signature parameter to the result of build_signature."""
254
 
        # Set the signature method.
255
 
        self.set_parameter('oauth_signature_method',
256
 
            signature_method.get_name())
257
 
        # Set the signature.
258
 
        self.set_parameter('oauth_signature',
259
 
            self.build_signature(signature_method, consumer, token))
260
 
 
261
 
    def build_signature(self, signature_method, consumer, token):
262
 
        """Calls the build signature method within the signature method."""
263
 
        return signature_method.build_signature(self, consumer, token)
264
 
 
265
 
    def from_request(http_method, http_url, headers=None, parameters=None,
266
 
            query_string=None):
267
 
        """Combines multiple parameter sources."""
268
 
        if parameters is None:
269
 
            parameters = {}
270
 
 
271
 
        # Headers
272
 
        if headers and 'Authorization' in headers:
273
 
            auth_header = headers['Authorization']
274
 
            # Check that the authorization header is OAuth.
275
 
            if auth_header[:6] == 'OAuth ':
276
 
                auth_header = auth_header[6:]
277
 
                try:
278
 
                    # Get the parameters from the header.
279
 
                    header_params = OAuthRequest._split_header(auth_header)
280
 
                    parameters.update(header_params)
281
 
                except:
282
 
                    raise OAuthError('Unable to parse OAuth parameters from '
283
 
                        'Authorization header.')
284
 
 
285
 
        # GET or POST query string.
286
 
        if query_string:
287
 
            query_params = OAuthRequest._split_url_string(query_string)
288
 
            parameters.update(query_params)
289
 
 
290
 
        # URL parameters.
291
 
        param_str = urlparse.urlparse(http_url)[4] # query
292
 
        url_params = OAuthRequest._split_url_string(param_str)
293
 
        parameters.update(url_params)
294
 
 
295
 
        if parameters:
296
 
            return OAuthRequest(http_method, http_url, parameters)
297
 
 
298
 
        return None
299
 
    from_request = staticmethod(from_request)
300
 
 
301
 
    def from_consumer_and_token(oauth_consumer, token=None,
302
 
            callback=None, verifier=None, http_method=HTTP_METHOD,
303
 
            http_url=None, parameters=None):
304
 
        if not parameters:
305
 
            parameters = {}
306
 
 
307
 
        defaults = {
308
 
            'oauth_consumer_key': oauth_consumer.key,
309
 
            'oauth_timestamp': generate_timestamp(),
310
 
            'oauth_nonce': generate_nonce(),
311
 
            'oauth_version': OAuthRequest.version,
312
 
        }
313
 
 
314
 
        defaults.update(parameters)
315
 
        parameters = defaults
316
 
 
317
 
        if token:
318
 
            parameters['oauth_token'] = token.key
319
 
            if token.callback:
320
 
                parameters['oauth_callback'] = token.callback
321
 
            # 1.0a support for verifier.
322
 
            if verifier:
323
 
                parameters['oauth_verifier'] = verifier
324
 
        elif callback:
325
 
            # 1.0a support for callback in the request token request.
326
 
            parameters['oauth_callback'] = callback
327
 
 
328
 
        return OAuthRequest(http_method, http_url, parameters)
329
 
    from_consumer_and_token = staticmethod(from_consumer_and_token)
330
 
 
331
 
    def from_token_and_callback(token, callback=None, http_method=HTTP_METHOD,
332
 
            http_url=None, parameters=None):
333
 
        if not parameters:
334
 
            parameters = {}
335
 
 
336
 
        parameters['oauth_token'] = token.key
337
 
 
338
 
        if callback:
339
 
            parameters['oauth_callback'] = callback
340
 
 
341
 
        return OAuthRequest(http_method, http_url, parameters)
342
 
    from_token_and_callback = staticmethod(from_token_and_callback)
343
 
 
344
 
    def _split_header(header):
345
 
        """Turn Authorization: header into parameters."""
346
 
        params = {}
347
 
        parts = header.split(',')
348
 
        for param in parts:
349
 
            # Ignore realm parameter.
350
 
            if param.find('realm') > -1:
351
 
                continue
352
 
            # Remove whitespace.
353
 
            param = param.strip()
354
 
            # Split key-value.
355
 
            param_parts = param.split('=', 1)
356
 
            # Remove quotes and unescape the value.
357
 
            params[param_parts[0]] = urllib.unquote(param_parts[1].strip('\"'))
358
 
        return params
359
 
    _split_header = staticmethod(_split_header)
360
 
 
361
 
    def _split_url_string(param_str):
362
 
        """Turn URL string into parameters."""
363
 
        parameters = cgi.parse_qs(param_str, keep_blank_values=False)
364
 
        for k, v in parameters.iteritems():
365
 
            parameters[k] = urllib.unquote(v[0])
366
 
        return parameters
367
 
    _split_url_string = staticmethod(_split_url_string)
368
 
 
369
 
class OAuthServer(object):
370
 
    """A worker to check the validity of a request against a data store."""
371
 
    timestamp_threshold = 300 # In seconds, five minutes.
372
 
    version = VERSION
373
 
    signature_methods = None
374
 
    data_store = None
375
 
 
376
 
    def __init__(self, data_store=None, signature_methods=None):
377
 
        self.data_store = data_store
378
 
        self.signature_methods = signature_methods or {}
379
 
 
380
 
    def set_data_store(self, data_store):
381
 
        self.data_store = data_store
382
 
 
383
 
    def get_data_store(self):
384
 
        return self.data_store
385
 
 
386
 
    def add_signature_method(self, signature_method):
387
 
        self.signature_methods[signature_method.get_name()] = signature_method
388
 
        return self.signature_methods
389
 
 
390
 
    def fetch_request_token(self, oauth_request):
391
 
        """Processes a request_token request and returns the
392
 
        request token on success.
393
 
        """
394
 
        try:
395
 
            # Get the request token for authorization.
396
 
            token = self._get_token(oauth_request, 'request')
397
 
        except OAuthError:
398
 
            # No token required for the initial token request.
399
 
            version = self._get_version(oauth_request)
400
 
            consumer = self._get_consumer(oauth_request)
401
 
            try:
402
 
                callback = self.get_callback(oauth_request)
403
 
            except OAuthError:
404
 
                callback = None # 1.0, no callback specified.
405
 
            self._check_signature(oauth_request, consumer, None)
406
 
            # Fetch a new token.
407
 
            token = self.data_store.fetch_request_token(consumer, callback)
408
 
        return token
409
 
 
410
 
    def fetch_access_token(self, oauth_request):
411
 
        """Processes an access_token request and returns the
412
 
        access token on success.
413
 
        """
414
 
        version = self._get_version(oauth_request)
415
 
        consumer = self._get_consumer(oauth_request)
416
 
        try:
417
 
            verifier = self._get_verifier(oauth_request)
418
 
        except OAuthError:
419
 
            verifier = None
420
 
        # Get the request token.
421
 
        token = self._get_token(oauth_request, 'request')
422
 
        self._check_signature(oauth_request, consumer, token)
423
 
        new_token = self.data_store.fetch_access_token(consumer, token, verifier)
424
 
        return new_token
425
 
 
426
 
    def verify_request(self, oauth_request):
427
 
        """Verifies an api call and checks all the parameters."""
428
 
        # -> consumer and token
429
 
        version = self._get_version(oauth_request)
430
 
        consumer = self._get_consumer(oauth_request)
431
 
        # Get the access token.
432
 
        token = self._get_token(oauth_request, 'access')
433
 
        self._check_signature(oauth_request, consumer, token)
434
 
        parameters = oauth_request.get_nonoauth_parameters()
435
 
        return consumer, token, parameters
436
 
 
437
 
    def authorize_token(self, token, user):
438
 
        """Authorize a request token."""
439
 
        return self.data_store.authorize_request_token(token, user)
440
 
 
441
 
    def get_callback(self, oauth_request):
442
 
        """Get the callback URL."""
443
 
        return oauth_request.get_parameter('oauth_callback')
444
 
 
445
 
    def build_authenticate_header(self, realm=''):
446
 
        """Optional support for the authenticate header."""
447
 
        return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
448
 
 
449
 
    def _get_version(self, oauth_request):
450
 
        """Verify the correct version request for this server."""
451
 
        try:
452
 
            version = oauth_request.get_parameter('oauth_version')
453
 
        except:
454
 
            version = VERSION
455
 
        if version and version != self.version:
456
 
            raise OAuthError('OAuth version %s not supported.' % str(version))
457
 
        return version
458
 
 
459
 
    def _get_signature_method(self, oauth_request):
460
 
        """Figure out the signature with some defaults."""
461
 
        try:
462
 
            signature_method = oauth_request.get_parameter(
463
 
                'oauth_signature_method')
464
 
        except:
465
 
            signature_method = SIGNATURE_METHOD
466
 
        try:
467
 
            # Get the signature method object.
468
 
            signature_method = self.signature_methods[signature_method]
469
 
        except:
470
 
            signature_method_names = ', '.join(self.signature_methods.keys())
471
 
            raise OAuthError('Signature method %s not supported try one of the '
472
 
                'following: %s' % (signature_method, signature_method_names))
473
 
 
474
 
        return signature_method
475
 
 
476
 
    def _get_consumer(self, oauth_request):
477
 
        consumer_key = oauth_request.get_parameter('oauth_consumer_key')
478
 
        consumer = self.data_store.lookup_consumer(consumer_key)
479
 
        if not consumer:
480
 
            raise OAuthError('Invalid consumer.')
481
 
        return consumer
482
 
 
483
 
    def _get_token(self, oauth_request, token_type='access'):
484
 
        """Try to find the token for the provided request token key."""
485
 
        token_field = oauth_request.get_parameter('oauth_token')
486
 
        token = self.data_store.lookup_token(token_type, token_field)
487
 
        if not token:
488
 
            raise OAuthError('Invalid %s token: %s' % (token_type, token_field))
489
 
        return token
490
 
    
491
 
    def _get_verifier(self, oauth_request):
492
 
        return oauth_request.get_parameter('oauth_verifier')
493
 
 
494
 
    def _check_signature(self, oauth_request, consumer, token):
495
 
        timestamp, nonce = oauth_request._get_timestamp_nonce()
496
 
        self._check_timestamp(timestamp)
497
 
        self._check_nonce(consumer, token, nonce)
498
 
        signature_method = self._get_signature_method(oauth_request)
499
 
        try:
500
 
            signature = oauth_request.get_parameter('oauth_signature')
501
 
        except:
502
 
            raise OAuthError('Missing signature.')
503
 
        # Validate the signature.
504
 
        valid_sig = signature_method.check_signature(oauth_request, consumer,
505
 
            token, signature)
506
 
        if not valid_sig:
507
 
            key, base = signature_method.build_signature_base_string(
508
 
                oauth_request, consumer, token)
509
 
            raise OAuthError('Invalid signature. Expected signature base '
510
 
                'string: %s' % base)
511
 
        built = signature_method.build_signature(oauth_request, consumer, token)
512
 
 
513
 
    def _check_timestamp(self, timestamp):
514
 
        """Verify that timestamp is recentish."""
515
 
        timestamp = int(timestamp)
516
 
        now = int(time.time())
517
 
        lapsed = abs(now - timestamp)
518
 
        if lapsed > self.timestamp_threshold:
519
 
            raise OAuthError('Expired timestamp: given %d and now %s has a '
520
 
                'greater difference than threshold %d' %
521
 
                (timestamp, now, self.timestamp_threshold))
522
 
 
523
 
    def _check_nonce(self, consumer, token, nonce):
524
 
        """Verify that the nonce is uniqueish."""
525
 
        nonce = self.data_store.lookup_nonce(consumer, token, nonce)
526
 
        if nonce:
527
 
            raise OAuthError('Nonce already used: %s' % str(nonce))
528
 
 
529
 
 
530
 
class OAuthClient(object):
531
 
    """OAuthClient is a worker to attempt to execute a request."""
532
 
    consumer = None
533
 
    token = None
534
 
 
535
 
    def __init__(self, oauth_consumer, oauth_token):
536
 
        self.consumer = oauth_consumer
537
 
        self.token = oauth_token
538
 
 
539
 
    def get_consumer(self):
540
 
        return self.consumer
541
 
 
542
 
    def get_token(self):
543
 
        return self.token
544
 
 
545
 
    def fetch_request_token(self, oauth_request):
546
 
        """-> OAuthToken."""
547
 
        raise NotImplementedError
548
 
 
549
 
    def fetch_access_token(self, oauth_request):
550
 
        """-> OAuthToken."""
551
 
        raise NotImplementedError
552
 
 
553
 
    def access_resource(self, oauth_request):
554
 
        """-> Some protected resource."""
555
 
        raise NotImplementedError
556
 
 
557
 
 
558
 
class OAuthDataStore(object):
559
 
    """A database abstraction used to lookup consumers and tokens."""
560
 
 
561
 
    def lookup_consumer(self, key):
562
 
        """-> OAuthConsumer."""
563
 
        raise NotImplementedError
564
 
 
565
 
    def lookup_token(self, oauth_consumer, token_type, token_token):
566
 
        """-> OAuthToken."""
567
 
        raise NotImplementedError
568
 
 
569
 
    def lookup_nonce(self, oauth_consumer, oauth_token, nonce):
570
 
        """-> OAuthToken."""
571
 
        raise NotImplementedError
572
 
 
573
 
    def fetch_request_token(self, oauth_consumer, oauth_callback):
574
 
        """-> OAuthToken."""
575
 
        raise NotImplementedError
576
 
 
577
 
    def fetch_access_token(self, oauth_consumer, oauth_token, oauth_verifier):
578
 
        """-> OAuthToken."""
579
 
        raise NotImplementedError
580
 
 
581
 
    def authorize_request_token(self, oauth_token, user):
582
 
        """-> OAuthToken."""
583
 
        raise NotImplementedError
584
 
 
585
 
 
586
 
class OAuthSignatureMethod(object):
587
 
    """A strategy class that implements a signature method."""
588
 
    def get_name(self):
589
 
        """-> str."""
590
 
        raise NotImplementedError
591
 
 
592
 
    def build_signature_base_string(self, oauth_request, oauth_consumer, oauth_token):
593
 
        """-> str key, str raw."""
594
 
        raise NotImplementedError
595
 
 
596
 
    def build_signature(self, oauth_request, oauth_consumer, oauth_token):
597
 
        """-> str."""
598
 
        raise NotImplementedError
599
 
 
600
 
    def check_signature(self, oauth_request, consumer, token, signature):
601
 
        built = self.build_signature(oauth_request, consumer, token)
602
 
        return built == signature
603
 
 
604
 
 
605
 
class OAuthSignatureMethod_HMAC_SHA1(OAuthSignatureMethod):
606
 
 
607
 
    def get_name(self):
608
 
        return 'HMAC-SHA1'
609
 
        
610
 
    def build_signature_base_string(self, oauth_request, consumer, token):
611
 
        sig = (
612
 
            escape(oauth_request.get_normalized_http_method()),
613
 
            escape(oauth_request.get_normalized_http_url()),
614
 
            escape(oauth_request.get_normalized_parameters()),
615
 
        )
616
 
 
617
 
        key = '%s&' % escape(consumer.secret)
618
 
        if token:
619
 
            key += escape(token.secret)
620
 
        raw = '&'.join(sig)
621
 
        return key, raw
622
 
 
623
 
    def build_signature(self, oauth_request, consumer, token):
624
 
        """Builds the base signature string."""
625
 
        key, raw = self.build_signature_base_string(oauth_request, consumer,
626
 
            token)
627
 
 
628
 
        # HMAC object.
629
 
        try:
630
 
            import hashlib # 2.5
631
 
            hashed = hmac.new(key, raw, hashlib.sha1)
632
 
        except:
633
 
            import sha # Deprecated
634
 
            hashed = hmac.new(key, raw, sha)
635
 
 
636
 
        # Calculate the digest base 64.
637
 
        return binascii.b2a_base64(hashed.digest())[:-1]
638
 
 
639
 
 
640
 
class OAuthSignatureMethod_PLAINTEXT(OAuthSignatureMethod):
641
 
 
642
 
    def get_name(self):
643
 
        return 'PLAINTEXT'
644
 
 
645
 
    def build_signature_base_string(self, oauth_request, consumer, token):
646
 
        """Concatenates the consumer key and secret."""
647
 
        sig = '%s&' % escape(consumer.secret)
648
 
        if token:
649
 
            sig = sig + escape(token.secret)
650
 
        return sig, sig
651
 
 
652
 
    def build_signature(self, oauth_request, consumer, token):
653
 
        key, raw = self.build_signature_base_string(oauth_request, consumer,
654
 
            token)
655
 
        return key