aboutsummaryrefslogtreecommitdiff
blob: b58fce7fe0fd80e59da2345e0d60a75a8d3e7e2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# vim:fileencoding=utf8:et:ts=4:sts=4:sw=4:ft=python

import base64
import calendar
import datetime

from django.db import IntegrityError
from django.utils import timezone

from openid.store.interface import OpenIDStore
from openid.association import Association
from openid.store import nonce

from okupy.accounts import models as db_models


class DjangoDBOpenIDStore(OpenIDStore):

    def storeAssociation(self, server_uri, assoc):
        issued_dt = datetime.datetime.utcfromtimestamp(assoc.issued)
        issued_dt = timezone.make_aware(issued_dt, timezone.utc)
        expire_delta = datetime.timedelta(seconds=assoc.lifetime)

        a = db_models.OpenID_Association(
            server_uri=server_uri,
            handle=assoc.handle,
            secret=base64.b64encode(assoc.secret),
            issued=issued_dt,
            expires=issued_dt + expire_delta,
            assoc_type=assoc.assoc_type)
        a.save()

    def _db_getAssocs(self, server_uri, handle=None):
        objs = db_models.OpenID_Association.objects
        objs = objs.filter(server_uri=server_uri)
        if handle is not None:
            objs = objs.filter(handle=handle)

        return objs

    def getAssociation(self, server_uri, handle=None):
        assert(server_uri is not None)

        objs = self._db_getAssocs(server_uri, handle)
        try:
            a = objs.latest('issued')
        except db_models.OpenID_Association.DoesNotExist:
            return None

        # expired?
        if timezone.now() >= a.expires:
            # if latest is expired, all older are expired as well
            # so clean them all up
            objs.delete()
            return None

        return Association(
            a.handle,
            base64.b64decode(a.secret),
            calendar.timegm(a.issued.utctimetuple()),
            int((a.expires - a.issued).total_seconds()),
            a.assoc_type)

    def removeAssociation(self, server_uri, handle):
        assert(server_uri is not None)
        assert(handle is not None)

        self._db_getAssocs(server_uri, handle)

        # determining whether something was deleted is a waste of time
        # and django doesn't give us explicit 'affected rows'
        return True

    def useNonce(self, server_uri, ts, salt):
        nonce_dt = datetime.datetime.utcfromtimestamp(ts)
        nonce_dt = timezone.make_aware(nonce_dt, timezone.utc)
        # copy-paste from python-openid's sqlstore
        if abs((nonce_dt - timezone.now()).total_seconds()) > nonce.SKEW:
            return False

        n = db_models.OpenID_Nonce(
            server_uri=server_uri,
            ts=nonce_dt,
            salt=salt)
        try:
            n.save()
        except IntegrityError:
            # non-unique
            return False
        return True

    def cleanupNonces(self):
        skew_td = datetime.timedelta(seconds=nonce.SKEW)
        expire_dt = timezone.now() - skew_td

        db_models.OpenID_Nonce.objects.filter(ts__lt=expire_dt).delete()
        return 0

    def cleanupAssociations(self):
        db_models.OpenID_Association.objects.filter(
            expires__lt=timezone.now()).delete()
        return 0