Commits

Jesper Nøhr committed 1b13975

oauth 1.0a compat, outsourcing secret/verifier generation to django, updating a few oauth models

Comments (0)

Files changed (5)

piston/authentication.py

 #       request.META['CONTENT_TYPE'] == "application/x-www-form-urlencoded":
         params = dict(request.REQUEST.items())
     else:
-        params = {}
+        params = { }
+
+    # Seems that we want to put HTTP_AUTHORIZATION into 'Authorization'
+    # for oauth.py to understand. Lovely.
+    request.META['Authorization'] = request.META.get('HTTP_AUTHORIZATION', '')
 
     oauth_request = oauth.OAuthRequest.from_request(
         request.method, request.build_absolute_uri(), 
 def oauth_auth_view(request, token, callback, params):
     form = forms.OAuthAuthenticationForm(initial={
         'oauth_token': token.key,
-        'oauth_callback': callback,
+        'oauth_callback': token.get_callback_url() or callback,
       })
 
     return render_to_response('piston/authorize_token.html',
         callback = oauth_server.get_callback(oauth_request)
     except:
         callback = None
-        
+    
     if request.method == "GET":
         params = oauth_request.get_normalized_parameters()
 

piston/emitters.py

         if not handler:
             return { }
 
-        has = dir(handler)
         ret = dict()
             
         for field in fields - Emitter.RESERVED_FIELDS:
 
 class OAuthAuthenticationForm(forms.Form):
     oauth_token = forms.CharField(widget=forms.HiddenInput)
-    oauth_callback = forms.CharField(widget=forms.HiddenInput)
+    oauth_callback = forms.CharField(widget=forms.HiddenInput, required=False)
     authorize_access = forms.BooleanField(required=True)
     csrf_signature = forms.CharField(widget=forms.HiddenInput)
 
-import urllib, time
+import urllib, time, urlparse
 
 # Django imports
 from django.db.models.signals import post_save, post_delete
 
 KEY_SIZE = 18
 SECRET_SIZE = 32
+VERIFIER_SIZE = 10
 
 CONSUMER_STATES = (
     ('pending', 'Pending'),
     ('rejected', 'Rejected')
 )
 
+def generate_random(length=SECRET_SIZE):
+    return User.objects.make_random_password(length=length)
+
 class Nonce(models.Model):
     token_key = models.CharField(max_length=KEY_SIZE)
     consumer_key = models.CharField(max_length=KEY_SIZE)
         c.generate_random_codes()
         """
         key = User.objects.make_random_password(length=KEY_SIZE)
-
-        secret = User.objects.make_random_password(length=SECRET_SIZE)
+        secret = generate_random(SECRET_SIZE)
 
         while Consumer.objects.filter(key__exact=key, secret__exact=secret).count():
-            secret = User.objects.make_random_password(length=SECRET_SIZE)
+            secret = generate_random(SECRET_SIZE)
 
         self.key = key
         self.secret = secret
     
     key = models.CharField(max_length=KEY_SIZE)
     secret = models.CharField(max_length=SECRET_SIZE)
+    verifier = models.CharField(max_length=VERIFIER_SIZE)
     token_type = models.IntegerField(choices=TOKEN_TYPES)
     timestamp = models.IntegerField(default=long(time.time()))
     is_approved = models.BooleanField(default=False)
     user = models.ForeignKey(User, null=True, blank=True, related_name='tokens')
     consumer = models.ForeignKey(Consumer)
     
+    callback = models.CharField(max_length=255, null=True, blank=True)
+    callback_confirmed = models.BooleanField(default=False)
+    
     objects = TokenManager()
     
     def __unicode__(self):
     def to_string(self, only_key=False):
         token_dict = {
             'oauth_token': self.key, 
-            'oauth_token_secret': self.secret
+            'oauth_token_secret': self.secret,
+            'oauth_callback_confirmed': 'true',
         }
+
+        if self.verifier:
+            token_dict.update({ 'oauth_verifier': self.verifier })
+
         if only_key:
             del token_dict['oauth_token_secret']
+
         return urllib.urlencode(token_dict)
 
     def generate_random_codes(self):
         key = User.objects.make_random_password(length=KEY_SIZE)
-        secret = User.objects.make_random_password(length=SECRET_SIZE)
+        secret = generate_random(SECRET_SIZE)
 
         while Token.objects.filter(key__exact=key, secret__exact=secret).count():
-            secret = User.objects.make_random_password(length=SECRET_SIZE)
+            secret = generate_random(SECRET_SIZE)
 
         self.key = key
         self.secret = secret
         self.save()
         
+    # -- OAuth 1.0a stuff
+
+    def get_callback_url(self):
+        if self.callback and self.verifier:
+            # Append the oauth_verifier.
+            parts = urlparse.urlparse(self.callback)
+            scheme, netloc, path, params, query, fragment = parts[:6]
+            if query:
+                query = '%s&oauth_verifier=%s' % (query, self.verifier)
+            else:
+                query = 'oauth_verifier=%s' % self.verifier
+            return urlparse.urlunparse((scheme, netloc, path, params,
+                query, fragment))
+        return self.callback
+    
+    def set_callback(self, callback):
+        if callback != "oob": # out of band, says "we can't do this!"
+            self.callback = callback
+            self.callback_confirmed = True
+            self.save()
+        
 admin.site.register(Token)
 
 # Attach our signals
 import oauth
 
 from models import Nonce, Token, Consumer
+from models import generate_random, VERIFIER_SIZE
 
 class DataStore(oauth.OAuthDataStore):
     """Layer between Python OAuth and Django database."""
             self.request_token = Token.objects.create_token(consumer=self.consumer,
                                                             token_type=Token.REQUEST,
                                                             timestamp=self.timestamp)
+            
+            if oauth_callback:
+                self.request_token.set_callback(oauth_callback)
+            
             return self.request_token
         return None
 
-    def fetch_access_token(self, oauth_consumer, oauth_token, oauth_callback):
+    def fetch_access_token(self, oauth_consumer, oauth_token, oauth_verifier):
         if oauth_consumer.key == self.consumer.key \
         and oauth_token.key == self.request_token.key \
+        and oauth_verifier == self.request_token.verifier \
         and self.request_token.is_approved:
             self.access_token = Token.objects.create_token(consumer=self.consumer,
                                                            token_type=Token.ACCESS,
             # authorize the request token in the store
             self.request_token.is_approved = True
             self.request_token.user = user
+            self.request_token.verifier = generate_random(VERIFIER_SIZE)
             self.request_token.save()
             return self.request_token
         return None