aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin/plugins/openid/store.py
blob: dd7947860c07d568cf1e08f0c62fdd15786f4372 (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011, 2012 MediaGoblin contributors.  See AUTHORS.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
import base64
import time

import six

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

from mediagoblin.plugins.openid.models import Association, Nonce


class SQLAlchemyOpenIDStore(OpenIDStore):
    def __init__(self):
        self.max_nonce_age = 6 * 60 * 60

    def storeAssociation(self, server_url, association):
        assoc = Association.query.filter_by(
            server_url=server_url, handle=association.handle
        ).first()

        if not assoc:
            assoc = Association()
            assoc.server_url = str(server_url)
            assoc.handle = association.handle

        # django uses base64 encoding, python-openid uses a blob field for
        # secret
        assoc.secret = str(base64.encodestring(association.secret))
        assoc.issued = association.issued
        assoc.lifetime = association.lifetime
        assoc.assoc_type = association.assoc_type
        assoc.save()

    def getAssociation(self, server_url, handle=None):
        assocs = []
        if handle is not None:
            assocs = Association.query.filter_by(
                server_url=server_url, handle=handle
            )
        else:
            assocs = Association.query.filter_by(
                server_url=server_url
            )

        if assocs.count() == 0:
            return None
        else:
            associations = []
            for assoc in assocs:
                association = OIDAssociation(
                    assoc.handle, base64.decodestring(assoc.secret),
                    assoc.issued, assoc.lifetime, assoc.assoc_type
                )
                if association.getExpiresIn() == 0:
                    assoc.delete()
                else:
                    associations.append((association.issued, association))

            if not associations:
                return None
            associations.sort()
            return associations[-1][1]

    def removeAssociation(self, server_url, handle):
        assocs = Association.query.filter_by(
            server_url=server_url, handle=handle
        ).first()

        assoc_exists = True if assocs else False
        for assoc in assocs:
            assoc.delete()
        return assoc_exists

    def useNonce(self, server_url, timestamp, salt):
        if abs(timestamp - time.time()) > nonce.SKEW:
            return False

        ononce = Nonce.query.filter_by(
            server_url=server_url,
            timestamp=timestamp,
            salt=salt
        ).first()

        if ononce:
            return False
        else:
            ononce = Nonce()
            ononce.server_url = server_url
            ononce.timestamp = timestamp
            ononce.salt = salt
            ononce.save()
            return True

    def cleanupNonces(self, _now=None):
        if _now is None:
            _now = int(time.time())
        expired = Nonce.query.filter(
            Nonce.timestamp < (_now - nonce.SKEW)
        )
        count = expired.count()
        for each in expired:
            each.delete()
        return count

    def cleanupAssociations(self):
        now = int(time.time())
        assoc = Association.query.all()
        count = 0
        for each in assoc:
            if (each.lifetime + each.issued) <= now:
                each.delete()
                count = count + 1
        return count