7c637d450e1af353c3230b82da9d74be560be6ca
[cascardo/ipsilon.git] / ipsilon / providers / openid / store.py
1 # Copyright (C) 2014 Ipsilon project Contributors, for license see COPYING
2
3 from ipsilon.util.data import Store, UNIQUE_DATA_TABLE, OPTIONS_TABLE
4
5 from openid import oidutil
6 from openid.association import Association
7 from openid.store.nonce import SKEW as NonceSKEW
8 from openid.store.interface import OpenIDStore as OpenIDStoreInterface
9
10 from time import time
11
12
13 class OpenIDStore(Store, OpenIDStoreInterface):
14     def __init__(self, database_url):
15         Store.__init__(self, database_url=database_url)
16
17     def storeAssociation(self, server_url, assoc):
18         iden = '%s-%s' % (server_url, assoc.handle)
19         datum = {'secret': oidutil.toBase64(assoc.secret),
20                  'issued': str(assoc.issued),
21                  'lifetime': str(assoc.lifetime),
22                  'assoc_type': assoc.assoc_type}
23
24         data = {iden: datum}
25         self.save_unique_data('association', data)
26
27     def getAssociation(self, server_url, handle=None):
28         iden = '%s-%s' % (server_url, handle)
29         data = self.get_unique_data('association', iden)
30
31         if len(data) < 1:
32             return None
33
34         datum = data[iden]
35         assoc = Association(handle,
36                             oidutil.fromBase64(datum['secret']),
37                             int(datum['issued']),
38                             int(datum['lifetime']),
39                             datum['assoc_type'])
40
41         if assoc.expiresIn == 0:
42             self.del_unique_data('association', iden)
43             return None
44
45         return assoc
46
47     def removeAssociation(self, server_url, handle):
48         iden = '%s-%s' % (server_url, handle)
49         self.del_unique_data('association', iden)
50
51     def useNonce(self, server_url, timestamp, salt):
52         if abs(timestamp - time()) > NonceSKEW:
53             return False
54
55         iden = '%s-%s-%s' % (server_url, timestamp, salt)
56         data = self.get_unique_data('nonce', iden)
57
58         if len(data) > 0:
59             # This server_url, timestamp, salt combination is already seen
60             return False
61
62         datum = {'timestamp': timestamp}
63         data = {iden: datum}
64         self.save_unique_data('nonce', data)
65
66         return True
67
68     def cleanupNonces(self):
69         nonces = self.get_unique_data('nonce')
70         for iden in nonces:
71             if nonces[iden]['timestamp'] < (time() - NonceSKEW):
72                 self.del_unique_data('nonce', iden)
73
74     def cleanupAssociations(self):
75         assocs = self.get_unique_data('association')
76         for iden in assocs:
77             if ((int(assocs[iden]['issued']) + int(assocs[iden]['lifetime']))
78                     < time()):
79                 self.del_unique_data('association', iden)
80
81     def _initialize_schema(self):
82         q = self._query(self._db, 'association', UNIQUE_DATA_TABLE,
83                         trans=False)
84         q.create()
85         q = self._query(self._db, 'openid_extensions', OPTIONS_TABLE,
86                         trans=False)
87         q.create()
88
89     def _upgrade_schema(self, old_version):
90         if old_version == 1:
91             # In schema version 2, we added indexes and primary keys
92             # pylint: disable=protected-access
93             table = self._query(self._db, 'association', UNIQUE_DATA_TABLE,
94                                 trans=False)._table
95             self._db.add_constraint(table.primary_key)
96             for index in table.indexes:
97                 self._db.add_index(index)
98             table = self._query(self._db, 'openid_extensions', OPTIONS_TABLE,
99                                 trans=False)._table
100             self._db.add_constraint(table.primary_key)
101             for index in table.indexes:
102                 self._db.add_index(index)
103             return 2
104         else:
105             raise NotImplementedError()