@@ -63,6 +63,22 @@ def build_authenticate_header(realm=''):
63
63
return {'WWW-Authenticate' : 'OAuth realm="%s"' % realm }
64
64
65
65
66
+ def build_xoauth_string (url , consumer , token = None ):
67
+ """Build an XOAUTH string for use in SMTP/IMPA authentication."""
68
+ request = oauth .Request .from_consumer_and_token (consumer , token ,
69
+ "GET" , url )
70
+
71
+ signing_method = oauth .SignatureMethod_HMAC_SHA1 ()
72
+ request .sign_request (signing_method , consumer , token )
73
+
74
+ params = []
75
+ for k ,v in sorted (request .iteritems ()):
76
+ if v is not None :
77
+ params .append ('%s="%s"' % (k , oauth .escape (v )))
78
+
79
+ return "%s %s %s" % ("GET" , url , ',' .join (params ))
80
+
81
+
66
82
def escape (s ):
67
83
"""Escape a URL including any /."""
68
84
return urllib .quote (s , safe = '~' )
@@ -473,6 +489,69 @@ def _split_url_string(param_str):
473
489
return parameters
474
490
475
491
492
+ class Client (httplib2 .Http ):
493
+ """OAuthClient is a worker to attempt to execute a request."""
494
+
495
+ def __init__ (self , consumer , token = None , cache = None , timeout = None ,
496
+ proxy_info = None ):
497
+
498
+ if consumer is not None and not isinstance (consumer , Consumer ):
499
+ raise ValueError ("Invalid consumer." )
500
+
501
+ if token is not None and not isinstance (token , Token ):
502
+ raise ValueError ("Invalid token." )
503
+
504
+ self .consumer = consumer
505
+ self .token = token
506
+ self .method = SignatureMethod_HMAC_SHA1 ()
507
+
508
+ httplib2 .Http .__init__ (self , cache = cache , timeout = timeout ,
509
+ proxy_info = proxy_info )
510
+
511
+ def set_signature_method (self , method ):
512
+ if not isinstance (method , SignatureMethod ):
513
+ raise ValueError ("Invalid signature method." )
514
+
515
+ self .method = method
516
+
517
+ def request (self , uri , method = "GET" , body = None , headers = None ,
518
+ redirections = httplib2 .DEFAULT_MAX_REDIRECTS , connection_type = None ):
519
+ DEFAULT_CONTENT_TYPE = 'application/x-www-form-urlencoded'
520
+
521
+ if not isinstance (headers , dict ):
522
+ headers = {}
523
+
524
+ is_multipart = method == 'POST' and headers .get ('Content-Type' ,
525
+ DEFAULT_CONTENT_TYPE ) != DEFAULT_CONTENT_TYPE
526
+
527
+ if body and method == "POST" and not is_multipart :
528
+ parameters = dict (parse_qsl (body ))
529
+ else :
530
+ parameters = None
531
+
532
+ req = Request .from_consumer_and_token (self .consumer ,
533
+ token = self .token , http_method = method , http_url = uri ,
534
+ parameters = parameters )
535
+
536
+ req .sign_request (self .method , self .consumer , self .token )
537
+
538
+ if method == "POST" :
539
+ headers ['Content-Type' ] = headers .get ('Content-Type' ,
540
+ DEFAULT_CONTENT_TYPE )
541
+ if is_multipart :
542
+ headers .update (req .to_header ())
543
+ else :
544
+ body = req .to_postdata ()
545
+ elif method == "GET" :
546
+ uri = req .to_url ()
547
+ else :
548
+ headers .update (req .to_header ())
549
+
550
+ return httplib2 .Http .request (self , uri , method = method , body = body ,
551
+ headers = headers , redirections = redirections ,
552
+ connection_type = connection_type )
553
+
554
+
476
555
class Server (object ):
477
556
"""A skeletal implementation of a service provider, providing protected
478
557
resources to requests from authorized consumers.
@@ -564,68 +643,8 @@ def _check_timestamp(self, timestamp):
564
643
lapsed = now - timestamp
565
644
if lapsed > self .timestamp_threshold :
566
645
raise Error ('Expired timestamp: given %d and now %s has a '
567
- 'greater difference than threshold %d' % (timestamp , now , self .timestamp_threshold ))
568
-
569
-
570
- class Client (httplib2 .Http ):
571
- """OAuthClient is a worker to attempt to execute a request."""
572
-
573
- def __init__ (self , consumer , token = None , cache = None , timeout = None ,
574
- proxy_info = None ):
575
-
576
- if consumer is not None and not isinstance (consumer , Consumer ):
577
- raise ValueError ("Invalid consumer." )
578
-
579
- if token is not None and not isinstance (token , Token ):
580
- raise ValueError ("Invalid token." )
581
-
582
- self .consumer = consumer
583
- self .token = token
584
- self .method = SignatureMethod_HMAC_SHA1 ()
585
-
586
- httplib2 .Http .__init__ (self , cache = cache , timeout = timeout ,
587
- proxy_info = proxy_info )
588
-
589
- def set_signature_method (self , method ):
590
- if not isinstance (method , SignatureMethod ):
591
- raise ValueError ("Invalid signature method." )
592
-
593
- self .method = method
594
-
595
- def request (self , uri , method = "GET" , body = None , headers = None ,
596
- redirections = httplib2 .DEFAULT_MAX_REDIRECTS , connection_type = None ):
597
- DEFAULT_CONTENT_TYPE = 'application/x-www-form-urlencoded'
598
-
599
- if not isinstance (headers , dict ):
600
- headers = {}
601
-
602
- is_multipart = method == 'POST' and headers .get ('Content-Type' , DEFAULT_CONTENT_TYPE ) != DEFAULT_CONTENT_TYPE
603
-
604
- if body and method == "POST" and not is_multipart :
605
- parameters = dict (parse_qsl (body ))
606
- else :
607
- parameters = None
608
-
609
- req = Request .from_consumer_and_token (self .consumer , token = self .token ,
610
- http_method = method , http_url = uri , parameters = parameters )
611
-
612
- req .sign_request (self .method , self .consumer , self .token )
613
-
614
-
615
- if method == "POST" :
616
- headers ['Content-Type' ] = headers .get ('Content-Type' , DEFAULT_CONTENT_TYPE )
617
- if is_multipart :
618
- headers .update (req .to_header ())
619
- else :
620
- body = req .to_postdata ()
621
- elif method == "GET" :
622
- uri = req .to_url ()
623
- else :
624
- headers .update (req .to_header ())
625
-
626
- return httplib2 .Http .request (self , uri , method = method , body = body ,
627
- headers = headers , redirections = redirections ,
628
- connection_type = connection_type )
646
+ 'greater difference than threshold %d' % (timestamp , now ,
647
+ self .timestamp_threshold ))
629
648
630
649
631
650
class SignatureMethod (object ):
0 commit comments