summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2014-09-10 17:19:55 -0400
committerPatrick Uiterwijk <puiterwijk@redhat.com>2014-09-24 20:51:24 +0200
commite0895efb26de64a28de7b9219f524b715c396b2b (patch)
tree06c114093b1ee22c1ed9a68e277666b9a2f3cc44
parent9e45a0dda4cfa26b531a423fc8b1c4b10d382a0f (diff)
downloadipsilon-e0895efb26de64a28de7b9219f524b715c396b2b.tar.gz
ipsilon-e0895efb26de64a28de7b9219f524b715c396b2b.tar.xz
ipsilon-e0895efb26de64a28de7b9219f524b715c396b2b.zip
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 <simo@redhat.com> Reviewed-by: Patrick Uiterwijk <puiterwijk@redhat.com>
-rwxr-xr-xipsilon/util/data.py15
-rwxr-xr-xipsilon/util/trans.py74
2 files changed, 89 insertions, 0 deletions
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)