From: Simo Sorce Date: Wed, 10 Sep 2014 21:19:55 +0000 (-0400) Subject: Add transactions support X-Git-Tag: v0.3.0~86 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Fipsilon.git;a=commitdiff_plain;h=e0895efb26de64a28de7b9219f524b715c396b2b Add transactions support In some cases a user may end up having multiple login pags in diffeent tabs in the borwser (session restore after a crash, or simply opening multiple urls which all redirect to the same IdP). Without transactions multiple authentication requests in fly may step on each other causing potentially all of them to fail to properly authenticate and redirect back to the original web site. Signed-off-by: Simo Sorce Reviewed-by: Patrick Uiterwijk --- diff --git a/ipsilon/util/data.py b/ipsilon/util/data.py index bdf93e7..5a144a4 100755 --- a/ipsilon/util/data.py +++ b/ipsilon/util/data.py @@ -348,3 +348,18 @@ class UserStore(Store): def save_user_preferences(self, user, options): return self.save_options('users', user, options) + + +class TranStore(Store): + + def __init__(self, path=None): + if path is None: + self._path = os.getcwd() + else: + self._path = path + self._name = None + if 'transactions.db' in cherrypy.config: + self._name = cherrypy.config['transactions.db'] + if not self._name: + self._name = os.path.join(self._path, 'transactions.sqlite') + super(TranStore, self).__init__(self._name) diff --git a/ipsilon/util/trans.py b/ipsilon/util/trans.py new file mode 100755 index 0000000..4d2f887 --- /dev/null +++ b/ipsilon/util/trans.py @@ -0,0 +1,74 @@ +#!/usr/bin/python +# +# Copyright (C) 2014 Ipsilon project Contributors, for licensee see COPYING + +from ipsilon.util.data import TranStore +from ipsilon.util.log import Log +from datetime import datetime +from ipsilon.util.cookies import SecureCookie + + +TRANSTABLE = 'transactions' +TRANSID = "ipsilon_transaction_id" + + +class Transaction(Log): + + def __init__(self, provider, **kwargs): + self.debug('Transaction: %s' % repr(kwargs)) + self.provider = provider + self.transaction_id = None + self._ts = TranStore() + self.cookie = None + tid = kwargs.get(TRANSID) + if tid: + self.transaction_id = tid + data = self._ts.get_unique_data(TRANSTABLE, tid) + self._get_cookie() + else: + data = {'provider': self.provider, + 'origintime': str(datetime.now())} + self.transaction_id = self._ts.new_unique_data(TRANSTABLE, data) + self._set_cookie() + self.debug('Transaction id: %s' % self.transaction_id) + + def _set_cookie(self): + self.cookie = SecureCookie(name=None, value=self.provider) + self.cookie.send() + cookiedata = {'cookie': self.cookie.name} + data = {self.transaction_id: cookiedata} + self._ts.save_unique_data(TRANSTABLE, data) + + def _get_cookie(self): + data = self.retrieve() + if 'cookie' not in data: + raise ValueError('Cookie name not available') + self.cookie = SecureCookie(data['cookie']) + self.cookie.receive() + if self.cookie.value is None: + raise ValueError('Missing or invalid cookie') + + def _del_cookie(self): + self.cookie.delete() + + def wipe(self): + if not self.transaction_id: + return + self._ts.del_unique_data(TRANSTABLE, self.transaction_id) + self._del_cookie() + self.transaction_id = None + + def store(self, data): + savedata = {self.transaction_id: data} + self._ts.save_unique_data(TRANSTABLE, savedata) + + def retrieve(self): + data = self._ts.get_unique_data(TRANSTABLE, + uuidval=self.transaction_id) + return data.get(self.transaction_id) + + def get_GET_arg(self): + return "%s=%s" % (TRANSID, self.transaction_id) + + def get_POST_tuple(self): + return (TRANSID, self.transaction_id)