~ubuntuone-pqm-team/canonical-identity-provider/trunk

« back to all changes in this revision

Viewing changes to identityprovider/models/openidmodels.py

  • Committer: Danny Tamez
  • Date: 2010-04-21 15:29:24 UTC
  • Revision ID: danny.tamez@canonical.com-20100421152924-lq1m92tstk2iz75a
Canonical SSO Provider (Open Source) - Initial Commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2010 Canonical Ltd.  This software is licensed under the
 
2
# GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 
 
4
import base64
 
5
import datetime
 
6
import time
 
7
 
 
8
from openid.association import Association
 
9
import openid.store
 
10
from openid.store.interface import OpenIDStore
 
11
 
 
12
from django.conf import settings
 
13
from django.db import models
 
14
from django.utils.translation import ugettext_lazy as _
 
15
 
 
16
from identityprovider.const import NEVER_EXPIRES, SREG_LABELS
 
17
from identityprovider.readonly import readonly_manager
 
18
from identityprovider.models import Account
 
19
from identityprovider.models.const import AccountCreationRationale
 
20
 
 
21
__all__ = (
 
22
    'OpenIDAssociation',
 
23
    'OpenIDAuthorization',
 
24
    'OpenIDNonce',
 
25
    'OpenIDRPConfig',
 
26
    'OpenIDRPSummary',
 
27
    'DjangoOpenIDStore',
 
28
)
 
29
 
 
30
 
 
31
class OpenIDAssociation(models.Model):
 
32
    server_url = models.CharField(max_length=2047)
 
33
    handle = models.CharField(max_length=255, primary_key=True)
 
34
    secret = models.TextField()  # This field type is a guess.
 
35
    issued = models.IntegerField()
 
36
    lifetime = models.IntegerField()
 
37
    assoc_type = models.CharField(max_length=64)
 
38
 
 
39
    class Meta:
 
40
        app_label = 'identityprovider'
 
41
        db_table = u'openidassociation'
 
42
        unique_together = ('server_url', 'handle')
 
43
 
 
44
 
 
45
class OpenIDAuthorizationManager(models.Manager):
 
46
 
 
47
    def authorize(self, account, trust_root, expires, client_id=None):
 
48
        if readonly_manager.is_readonly():
 
49
            return
 
50
        if expires is None:
 
51
            expires = NEVER_EXPIRES
 
52
        try:
 
53
            existing = OpenIDAuthorization.objects.get(
 
54
                account=account,
 
55
                client_id=client_id,
 
56
                trust_root=trust_root)
 
57
            existing.date_created = datetime.datetime.utcnow()
 
58
            existing.date_expires = expires
 
59
            existing.save()
 
60
        except OpenIDAuthorization.DoesNotExist:
 
61
            OpenIDAuthorization.objects.create(
 
62
                account=account,
 
63
                client_id=client_id,
 
64
                trust_root=trust_root,
 
65
                date_expires=expires)
 
66
 
 
67
    def is_authorized(self, account, trust_root, client_id):
 
68
        client_none = OpenIDAuthorization.objects.filter(
 
69
            account__exact=account,
 
70
            trust_root__exact=trust_root,
 
71
            client_id__exact=None,
 
72
            date_expires__gte=datetime.datetime.utcnow()).count()
 
73
        if client_none > 0:
 
74
            return True
 
75
        else:
 
76
            client_match = OpenIDAuthorization.objects.filter(
 
77
                account__exact=account,
 
78
                trust_root__exact=trust_root,
 
79
                client_id__exact=client_id,
 
80
                date_expires__gte=datetime.datetime.utcnow()).count()
 
81
            if client_match > 0:
 
82
                return True
 
83
        return False
 
84
 
 
85
 
 
86
class OpenIDAuthorization(models.Model):
 
87
    account = models.ForeignKey(Account, db_column='account')
 
88
    client_id = models.TextField(blank=True, null=True)
 
89
    date_created = models.DateTimeField(default=datetime.datetime.utcnow,
 
90
        blank=True, editable=False)
 
91
    date_expires = models.DateTimeField()
 
92
    trust_root = models.TextField()
 
93
 
 
94
    objects = OpenIDAuthorizationManager()
 
95
 
 
96
    class Meta:
 
97
        app_label = 'identityprovider'
 
98
        db_table = u'openidauthorization'
 
99
 
 
100
 
 
101
class OpenIDNonce(models.Model):
 
102
    server_url = models.CharField(max_length=2047, primary_key=True)
 
103
    timestamp = models.IntegerField()
 
104
    salt = models.CharField(max_length=40)
 
105
 
 
106
    class Meta:
 
107
        app_label = 'identityprovider'
 
108
        db_table = 'openidnonce'
 
109
        unique_together = ('server_url', 'timestamp', 'salt')
 
110
 
 
111
 
 
112
class OpenIDRPConfig(models.Model):
 
113
    trust_root = models.TextField(unique=True)
 
114
    displayname = models.TextField()
 
115
    description = models.TextField()
 
116
    logo = models.TextField(blank=True, null=True)
 
117
    allowed_sreg = models.TextField(blank=True, null=True,
 
118
        choices=SREG_LABELS.items())
 
119
    creation_rationale = models.IntegerField(default=13,
 
120
        choices=AccountCreationRationale._get_choices())
 
121
    can_query_any_team = models.BooleanField(default=False)
 
122
    auto_authorize = models.BooleanField(default=False)
 
123
 
 
124
    class Meta:
 
125
        app_label = 'identityprovider'
 
126
        db_table = 'ssoopenidrpconfig'
 
127
        verbose_name = _('OpenID RP Config')
 
128
        verbose_name_plural = _('OpenID RP Configs')
 
129
 
 
130
    def __unicode__(self):
 
131
        return self.displayname
 
132
 
 
133
    @property
 
134
    def logo_url(self):
 
135
        if self.logo:
 
136
            return settings.MEDIA_URL + self.logo
 
137
        else:
 
138
            return None
 
139
 
 
140
 
 
141
class OpenIDRPSummaryManager(models.Manager):
 
142
 
 
143
    def record(self, account, trust_root, openid_identifier=None):
 
144
        if readonly_manager.is_readonly():
 
145
            return None
 
146
        if openid_identifier is None:
 
147
            openid_identifier = account.openid_identity_url
 
148
        try:
 
149
            summary = OpenIDRPSummary.objects.get(
 
150
                account=account,
 
151
                trust_root=trust_root,
 
152
                openid_identifier=openid_identifier)
 
153
            summary.increment()
 
154
        except OpenIDRPSummary.DoesNotExist:
 
155
            summary = OpenIDRPSummary.objects.create(
 
156
                account=account,
 
157
                trust_root=trust_root,
 
158
                openid_identifier=openid_identifier)
 
159
        return summary
 
160
 
 
161
 
 
162
class OpenIDRPSummary(models.Model):
 
163
    account = models.ForeignKey(Account, db_column='account')
 
164
    openid_identifier = models.TextField()
 
165
    trust_root = models.TextField()
 
166
    date_created = models.DateTimeField(default=datetime.datetime.utcnow,
 
167
        blank=True, editable=False)
 
168
    date_last_used = models.DateTimeField(default=datetime.datetime.utcnow,
 
169
        blank=True, editable=False)
 
170
    total_logins = models.IntegerField(default=1)
 
171
 
 
172
    objects = OpenIDRPSummaryManager()
 
173
 
 
174
    class Meta:
 
175
        app_label = 'identityprovider'
 
176
        db_table = u'openidrpsummary'
 
177
        unique_together = ('account', 'trust_root', 'openid_identifier')
 
178
 
 
179
    def increment(self):
 
180
        self.total_logins += 1
 
181
        self.date_last_used = datetime.datetime.utcnow()
 
182
        self.save()
 
183
 
 
184
 
 
185
class DjangoOpenIDStore(OpenIDStore):
 
186
    """
 
187
    The Python openid library needs an OpenIDStore subclass to persist data
 
188
    related to OpenID authentications. This one uses our Django models.
 
189
 
 
190
    From: http://code.google.com/p/django-openid/source/browse/trunk/django_openid/models.py
 
191
 
 
192
    Please see the license file in thirdparty/django-openid.
 
193
    """
 
194
 
 
195
    def storeAssociation(self, server_url, association):
 
196
        try:
 
197
            assoc = OpenIDAssociation.objects.get(
 
198
                server_url=server_url,
 
199
                handle=association.handle)
 
200
            assoc.secret = base64.b64encode(association.secret)
 
201
            assoc.issued = association.issued
 
202
            assoc.lifetime = association.getExpiresIn()
 
203
            assoc.assoc_type = association.assoc_type
 
204
        except OpenIDAssociation.DoesNotExist:
 
205
            assoc = OpenIDAssociation(
 
206
                server_url=server_url,
 
207
                handle=association.handle,
 
208
                secret=base64.b64encode(association.secret),
 
209
                issued=association.issued,
 
210
                lifetime=association.getExpiresIn(),
 
211
                assoc_type=association.assoc_type)
 
212
        assoc.save()
 
213
 
 
214
    def getAssociation(self, server_url, handle=None):
 
215
        assocs = []
 
216
        if handle is not None:
 
217
            assocs = OpenIDAssociation.objects.filter(
 
218
                server_url=server_url,
 
219
                handle=handle
 
220
            )
 
221
        else:
 
222
            assocs = OpenIDAssociation.objects.filter(
 
223
                server_url=server_url)
 
224
        if not assocs:
 
225
            return None
 
226
        associations = []
 
227
        for assoc in assocs:
 
228
            association = Association(
 
229
                assoc.handle, base64.b64decode(str(assoc.secret)),
 
230
                assoc.issued, assoc.lifetime, assoc.assoc_type)
 
231
            if association.getExpiresIn() == 0:
 
232
                self.removeAssociation(server_url, assoc.handle)
 
233
            else:
 
234
                associations.append((association.issued, association))
 
235
        if not associations:
 
236
            return None
 
237
        return associations[-1][1]
 
238
 
 
239
    def removeAssociation(self, server_url, handle):
 
240
        assocs = list(OpenIDAssociation.objects.filter(
 
241
            server_url=server_url, handle=handle))
 
242
        assocs_exist = len(assocs) > 0
 
243
        for assoc in assocs:
 
244
            assoc.delete()
 
245
        return assocs_exist
 
246
 
 
247
    def useNonce(self, server_url, timestamp, salt):
 
248
        # Has nonce expired?
 
249
        if abs(timestamp - time.time()) > openid.store.nonce.SKEW:
 
250
            return False
 
251
        try:
 
252
            nonce = OpenIDNonce.objects.get(
 
253
                server_url__exact=server_url,
 
254
                timestamp__exact=timestamp,
 
255
                salt__exact=salt)
 
256
        except OpenIDNonce.DoesNotExist:
 
257
            nonce = OpenIDNonce.objects.create(
 
258
                server_url=server_url,
 
259
                timestamp=timestamp,
 
260
                salt=salt)
 
261
            return True
 
262
        nonce.delete()
 
263
        return False
 
264
 
 
265
    def cleanupNonce(self):
 
266
        OpenIDNonce.objects.filter(
 
267
            timestamp__lt=(
 
268
                int(time.time()) - openid.store.nonce.SKEW)).delete()
 
269
 
 
270
    def cleanupAssociations(self):
 
271
        OpenIDAssociation.objects.extra(
 
272
            where=[
 
273
                'issued + lifetimeint < (%s)' % time.time()]).delete()