david / django-oauth (http://oauth.net/)

Support of OAuth in Django. Note that http://code.welldev.org/django-oauth-plus will use python-oauth2 if you're interested in it.

Clone this repository (size: 114.7 KB): HTTPS / SSH
$ hg clone http://code.welldev.org/django-oauth
commit 28: 8579a1562b16
parent 27: c038f3e47c5f
branch: default
Update models (stolen from piston) to be 1.0a ready, note that it will affect your Token/Consumer tables
David Larlet / david
12 months ago
    #   Introduced
1
c3ff630fbbb4
import urllib
2
8579a1562b16
import urlparse
3
8579a1562b16
from time import time
4
c3ff630fbbb4
5
c3ff630fbbb4
from django.db import models
6
c3ff630fbbb4
from django.contrib.auth.models import User
7
c3ff630fbbb4
8
c3ff630fbbb4
from managers import TokenManager, ConsumerManager, ResourceManager
9
8579a1562b16
from consts import KEY_SIZE, SECRET_SIZE, CONSUMER_KEY_SIZE, CONSUMER_STATES,\
10
8579a1562b16
                   PENDING, VERIFIER_SIZE
11
c3ff630fbbb4
12
8579a1562b16
generate_random = User.objects.make_random_password
13
c3ff630fbbb4
14
c3ff630fbbb4
class Nonce(models.Model):
15
c3ff630fbbb4
    token_key = models.CharField(max_length=KEY_SIZE)
16
f6dd3126f023
    consumer_key = models.CharField(max_length=CONSUMER_KEY_SIZE)
17
c3ff630fbbb4
    key = models.CharField(max_length=255)
18
c3ff630fbbb4
    
19
c3ff630fbbb4
    def __unicode__(self):
20
c3ff630fbbb4
        return u"Nonce %s for %s" % (self.key, self.consumer_key)
21
c3ff630fbbb4
22
c3ff630fbbb4
23
c3ff630fbbb4
class Resource(models.Model):
24
c3ff630fbbb4
    name = models.CharField(max_length=255)
25
c3ff630fbbb4
    url = models.TextField(max_length=2047)
26
c3ff630fbbb4
    is_readonly = models.BooleanField(default=True)
27
c3ff630fbbb4
    
28
c3ff630fbbb4
    objects = ResourceManager()
29
c3ff630fbbb4
30
c3ff630fbbb4
    def __unicode__(self):
31
c3ff630fbbb4
        return u"Resource %s with url %s" % (self.name, self.url)
32
c3ff630fbbb4
33
c3ff630fbbb4
34
c3ff630fbbb4
class Consumer(models.Model):
35
c3ff630fbbb4
    name = models.CharField(max_length=255)
36
8579a1562b16
    description = models.TextField()
37
8579a1562b16
    
38
f6dd3126f023
    key = models.CharField(max_length=CONSUMER_KEY_SIZE)
39
616f3b587327
    secret = models.CharField(max_length=SECRET_SIZE, blank=True)
40
8579a1562b16
41
8579a1562b16
    status = models.SmallIntegerField(choices=CONSUMER_STATES, default=PENDING)
42
c3ff630fbbb4
    user = models.ForeignKey(User, null=True, blank=True)
43
c3ff630fbbb4
44
c3ff630fbbb4
    objects = ConsumerManager()
45
c3ff630fbbb4
        
46
c3ff630fbbb4
    def __unicode__(self):
47
c3ff630fbbb4
        return u"Consumer %s with key %s" % (self.name, self.key)
48
c3ff630fbbb4
49
c3ff630fbbb4
    def generate_random_codes(self):
50
8579a1562b16
        """
51
8579a1562b16
        Used to generate random key/secret pairings.
52
8579a1562b16
        Use this after you've added the other data in place of save().
53
8579a1562b16
        """
54
8579a1562b16
        key = generate_random(length=KEY_SIZE)
55
8579a1562b16
        secret = generate_random(length=SECRET_SIZE)
56
c3ff630fbbb4
        while Consumer.objects.filter(key__exact=key, secret__exact=secret).count():
57
8579a1562b16
            secret = generate_random(length=SECRET_SIZE)
58
c3ff630fbbb4
        self.key = key
59
c3ff630fbbb4
        self.secret = secret
60
c3ff630fbbb4
        self.save()
61
c3ff630fbbb4
62
c3ff630fbbb4
63
c3ff630fbbb4
class Token(models.Model):
64
c3ff630fbbb4
    REQUEST = 1
65
c3ff630fbbb4
    ACCESS = 2
66
c3ff630fbbb4
    TOKEN_TYPES = ((REQUEST, u'Request'), (ACCESS, u'Access'))
67
c3ff630fbbb4
    
68
c3ff630fbbb4
    key = models.CharField(max_length=KEY_SIZE)
69
c3ff630fbbb4
    secret = models.CharField(max_length=SECRET_SIZE)
70
8579a1562b16
    token_type = models.SmallIntegerField(choices=TOKEN_TYPES)
71
8579a1562b16
    timestamp = models.IntegerField(default=long(time()))
72
c3ff630fbbb4
    is_approved = models.BooleanField(default=False)
73
c3ff630fbbb4
    
74
8579a1562b16
    user = models.ForeignKey(User, null=True, blank=True, related_name='tokens')
75
c3ff630fbbb4
    consumer = models.ForeignKey(Consumer)
76
c3ff630fbbb4
    resource = models.ForeignKey(Resource)
77
c3ff630fbbb4
    
78
8579a1562b16
    ## OAuth 1.0a stuff
79
8579a1562b16
    verifier = models.CharField(max_length=VERIFIER_SIZE)
80
8579a1562b16
    callback = models.CharField(max_length=255, null=True, blank=True)
81
8579a1562b16
    callback_confirmed = models.BooleanField(default=False)
82
8579a1562b16
    
83
c3ff630fbbb4
    objects = TokenManager()
84
c3ff630fbbb4
    
85
c3ff630fbbb4
    def __unicode__(self):
86
c3ff630fbbb4
        return u"%s Token %s for %s" % (self.get_token_type_display(), self.key, self.consumer)
87
c3ff630fbbb4
88
c3ff630fbbb4
    def to_string(self, only_key=False):
89
c3ff630fbbb4
        token_dict = {
90
c3ff630fbbb4
            'oauth_token': self.key, 
91
8579a1562b16
            'oauth_token_secret': self.secret,
92
8579a1562b16
            'oauth_callback_confirmed': 'true',
93
c3ff630fbbb4
        }
94
8579a1562b16
        if self.verifier:
95
8579a1562b16
            token_dict.update({ 'oauth_verifier': self.verifier })
96
8579a1562b16
97
c3ff630fbbb4
        if only_key:
98
c3ff630fbbb4
            del token_dict['oauth_token_secret']
99
8579a1562b16
100
c3ff630fbbb4
        return urllib.urlencode(token_dict)
101
c3ff630fbbb4
102
c3ff630fbbb4
    def generate_random_codes(self):
103
8579a1562b16
        """
104
8579a1562b16
        Used to generate random key/secret pairings. 
105
8579a1562b16
        Use this after you've added the other data in place of save(). 
106
8579a1562b16
        """
107
8579a1562b16
        key = generate_random(length=KEY_SIZE)
108
8579a1562b16
        secret = generate_random(length=SECRET_SIZE)
109
c3ff630fbbb4
        while Token.objects.filter(key__exact=key, secret__exact=secret).count():
110
8579a1562b16
            secret = generate_random(length=SECRET_SIZE)
111
c3ff630fbbb4
        self.key = key
112
c3ff630fbbb4
        self.secret = secret
113
c3ff630fbbb4
        self.save()
114
8579a1562b16
115
8579a1562b16
    ## OAuth 1.0a stuff
116
8579a1562b16
117
8579a1562b16
    def get_callback_url(self):
118
8579a1562b16
        if self.callback and self.verifier:
119
8579a1562b16
            # Append the oauth_verifier.
120
8579a1562b16
            parts = urlparse.urlparse(self.callback)
121
8579a1562b16
            scheme, netloc, path, params, query, fragment = parts[:6]
122
8579a1562b16
            if query:
123
8579a1562b16
                query = '%s&oauth_verifier=%s' % (query, self.verifier)
124
8579a1562b16
            else:
125
8579a1562b16
                query = 'oauth_verifier=%s' % self.verifier
126
8579a1562b16
            return urlparse.urlunparse((scheme, netloc, path, params,
127
8579a1562b16
                query, fragment))
128
8579a1562b16
        return self.callback
129
8579a1562b16
    
130
8579a1562b16
    def set_callback(self, callback):
131
8579a1562b16
        if callback != "oob": # out of band, says "we can't do this!"
132
8579a1562b16
            self.callback = callback
133
8579a1562b16
            self.callback_confirmed = True
134
8579a1562b16
            self.save()