pam: use a pam object method instead of pam module function
[cascardo/ipsilon.git] / ipsilon / util / sessions.py
1 # Copyright (C) 2014 Ipsilon project Contributors, for license see COPYING
2
3 import base64
4 from cherrypy.lib.sessions import Session
5 from ipsilon.util.data import Store, SqlQuery
6 import threading
7 import datetime
8 try:
9     import cPickle as pickle
10 except ImportError:
11     import pickle
12
13
14 SESSION_TABLE = {'columns': ['id', 'data', 'expiration_time'],
15                  'primary_key': ('id', ),
16                  'indexes': [('expiration_time',)]
17                  }
18
19
20 class SessionStore(Store):
21     def _initialize_schema(self):
22         q = self._query(self._db, 'sessions', SESSION_TABLE,
23                         trans=False)
24         q.create()
25         q._con.close()  # pylint: disable=protected-access
26
27     def _upgrade_schema(self, old_version):
28         if old_version == 1:
29             # In schema version 2, we added indexes and primary keys
30             # pylint: disable=protected-access
31             table = self._query(self._db, 'sessions', SESSION_TABLE,
32                                 trans=False)._table
33             self._db.add_constraint(table.primary_key)
34             for index in table.indexes:
35                 self._db.add_index(index)
36             return 2
37         else:
38             raise NotImplementedError()
39
40     def _cleanup(self):
41         # pylint: disable=protected-access
42         table = SqlQuery(self._db, 'sessions', SESSION_TABLE)._table
43         # pylint: disable=no-value-for-parameter
44         d = table.delete().where(table.c.expiration_time
45                                  <= datetime.datetime.now())
46         return d.execute().rowcount
47
48
49 class SqlSession(Session):
50
51     dburi = None
52     _db = None
53     _store = None
54     _proto = 2
55     locks = {}
56
57     @classmethod
58     def setup(cls, **kwargs):
59         """Initialization from cherrypy"""
60
61         for k, v in kwargs.items():
62             if k == 'storage_dburi':
63                 cls.dburi = v
64
65         cls._store = SessionStore(database_url=cls.dburi)
66         # pylint: disable=protected-access
67         cls._db = cls._store._db
68
69     def _exists(self):
70         q = SqlQuery(self._db, 'sessions', SESSION_TABLE)
71         result = q.select({'id': self.id})
72         return True if result.fetchone() else False
73
74     def _load(self):
75         q = SqlQuery(self._db, 'sessions', SESSION_TABLE)
76         result = q.select({'id': self.id})
77         r = result.fetchone()
78         if r:
79             data = str(base64.b64decode(r[1]))
80             return pickle.loads(data)
81
82     def _save(self, expiration_time):
83         q = None
84         try:
85             q = SqlQuery(self._db, 'sessions', SESSION_TABLE, trans=True)
86             q.delete({'id': self.id})
87             data = pickle.dumps((self._data, expiration_time), self._proto)
88             q.insert((self.id, base64.b64encode(data), expiration_time))
89             q.commit()
90         except Exception:  # pylint: disable=broad-except
91             if q:
92                 q.rollback()
93             raise
94
95     def _delete(self):
96         q = SqlQuery(self._db, 'sessions', SESSION_TABLE)
97         q.delete({'id': self.id})
98
99     # copy what RamSession does for now
100     def acquire_lock(self):
101         """Acquire an exclusive lock on the currently-loaded session data."""
102         self.locked = True
103         self.locks.setdefault(self.id, threading.RLock()).acquire()
104
105     def release_lock(self):
106         """Release the lock on the currently-loaded session data."""
107         self.locks[self.id].release()
108         self.locked = False