This repository has been archived on 2021-09-15. You can view files and clone it, but cannot push or open issues or pull requests.
DUT2PTUT/session.py

148 lines
5.1 KiB
Python

"""
Usage:
In your application script,
settings["session_secret"] = 'some secret password!!'
settings["session_dir"] = 'sessions' # the directory to store sessions in
application.session_manager = session.TornadoSessionManager(settings["session_secret"], settings["session_dir"])
In your RequestHandler (probably in __init__),
self.session = session.TornadoSession(self.application.session_manager, self)
After that, you can use it like this (in get(), post(), etc):
self.session['blah'] = 1234
self.save()
blah = self.session['blah']
etc.
the basic session mechanism is this:
* take some data, pickle it, store it somewhere.
* assign an id to it. run that id through a HMAC (NOT just a hash function) to prevent tampering.
* put the id and HMAC output in a cookie.
* when you get a request, load the id, verify the HMAC. if it matches, load the data from wherever you put it and depickle it.
"""
import pickle
import os.path
import hmac
import hashlib
import uuid
class Session(dict):
""" A Session is basically a dict with a session_id and an hmac_digest string to verify access rights """
def __init__(self, session_id, hmac_digest):
self.session_id = session_id
self.hmac_digest = hmac_digest
class SessionManager(object):
""" SessionManager handles the cookie and file read/writes for a Session """
def __init__(self, secret, session_dir = ''):
self.secret = secret
# figure out where to store the session file
if session_dir == '':
session_dir = os.path.join(os.path.dirname(__file__), 'sessions')
self.session_dir = session_dir
def _read(self, session_id):
session_path = self._get_session_path(session_id)
try :
data = pickle.load(open(session_path))
if type(data) == type({}):
return data
else:
return {}
except IOError:
return {}
def get(self, session_id = None, hmac_digest = None):
# set up the session state (create it from scratch, or from parameters
if session_id == None:
session_should_exist = False
session_id = self._generate_uid()
hmac_digest = self._get_hmac_digest(session_id)
else:
session_should_exist = True
session_id = session_id
hmac_digest = hmac_digest # keyed-Hash Message Authentication Code
# make sure the HMAC digest we generate matches the given one, to validate
expected_hmac_digest = self._get_hmac_digest(session_id)
if hmac_digest != expected_hmac_digest:
raise InvalidSessionException()
# create the session object
session = Session(session_id, hmac_digest)
# read the session file, if this is a pre-existing session
if session_should_exist:
data = self._read(session_id)
for i, j in data.iteritems():
session[i] = j
return session
def _get_session_path(self, session_id):
return os.path.join(self.session_dir, 'SESSION' + str(session_id))
def set(self, session):
session_path = self._get_session_path(session.session_id)
session_file = open(session_path, 'wb')
pickle.dump(dict(session.items()), session_file)
session_file.close()
def _get_hmac_digest(self, session_id):
return hmac.new(session_id, self.secret, hashlib.sha1).hexdigest()
def _generate_uid(self):
base = hashlib.md5( self.secret + str(uuid.uuid4()) )
return base.hexdigest()
class TornadoSessionManager(SessionManager):
""" A TornadoSessionManager is a SessionManager that is specifically for use in Tornado, using Tornado's cookies """
def get(self, requestHandler = None):
if requestHandler == None:
return super(TornadoSessionManager, self).get()
else:
session_id = requestHandler.get_secure_cookie("session_id")
hmac_digest = requestHandler.get_secure_cookie("hmac_digest")
return super(TornadoSessionManager, self).get(session_id, hmac_digest)
def set(self, requestHandler, session):
requestHandler.set_secure_cookie("session_id", session.session_id)
requestHandler.set_secure_cookie("hmac_digest", session.hmac_digest)
return super(TornadoSessionManager, self).set(session)
class TornadoSession(Session):
""" A TornadoSession is a Session object for use in Tornado """
def __init__(self, tornado_session_manager, request_handler):
self.session_manager = tornado_session_manager
self.request_handler = request_handler
# get the session object's data and transfer it to this session item
try:
plain_session = tornado_session_manager.get(request_handler)
except InvalidSessionException:
plain_session = tornado_session_manager.get()
for i, j in plain_session.iteritems():
self[i] = j
self.session_id = plain_session.session_id
self.hmac_digest = plain_session.hmac_digest
def save(self):
self.session_manager.set(self.request_handler, self)
class InvalidSessionException(Exception):
pass