1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
"""A server-side module for sessions in HTTP/HTTPS by
giving/getting a magic cookie from the browser, which
is simply a reference to a local data storage."""
# $Id: session.py,v 1.1 2003/01/18 05:29:16 stain Exp $
#
# Strongly inspired by PHP4's sessions.
# (c) Stian Soiland <stain@nvg.org> 2001
# Licence: LGPL
#
# Last changes:
# $Log: session.py,v $
# Revision 1.1 2003/01/18 05:29:16 stain
# First import from aapningstider.no
#
# Revision 1.1 2002/07/18 23:12:02 stain
# Akkai
#
# Revision 1.6 2002/04/08 01:58:54 stain
# I couldn't sleep and for some reason decided to change this module's
# ID-generation method. It's a bit easier then just lying in the dark
# thinking about girl problems.
#
#
# New method:
#
# Chooses 20 random characters from the readable part of the 7-bit ascii,
# ie, from chr(32) till chr(126) inclusive.
#
# This yields approximately 2**128 variations. Actually it yields 95**20
# == 3584859224085422343574104404449462890625 ~= 2**131 variations.
#
# This of course is based on a 'perfect' random generator, which we don't
# have. Note that the basic idea is to have a ID that is hard to guess. If
# you have a system with 2**64 different sessions registered (unthinkable!
# Calculate the number!) - an attacker would need to do 2**64
#
# (??? Shouldn't this number be calculated in a bit trickier way?)
#
# connection attempts in order to retrieve an usable ID
# - and then he still wouldn't have any way to decide which ID to
# retrieve.
#
#
# Other suggestions: (involves uglier programming)
#
# Calculate a number 2L**128 large by selecting four integers at random,
# putting them together by bitshifting 32, 64 and 96 bits and thereafter
# adding/and-ing them together.
#
# Then - use as a string. (you would probably need to do C-stuff to do
# this, bitshifting and adding letters with chr() would be STUPID), and
# THEN again, convert to base64.
#
# This method would use more processing power, look stupider and uglier,
# but would only use 4 random calls instead of 20. This could
#
# a) Reduce total processing time if the randomizer is very CPU and/or
# hardware intensive
#
# b) Reduce possible patterns caused by imperfect random generators, and
# thereby making the result 'more random'
#
# Revision 1.5 2001/04/10 00:11:08 stain
# Support for expiration (ie. sessions stored between browser
# instances)
#
# Revision 1.4 2001/04/06 19:36:38 stain
# Noe er endret.
#
# Revision 1.3 2001/03/13 23:45:07 stain
# N virker den.
#
#
# Todo:
# + Maybe check that the session does not exist already
import Cookie,os,random,UserDict,pickle,time
class Session(UserDict.UserDict):
def __init__(self, identifier=None, valid=None):
"""Initializes a new session or restores the old one.
Identifier is used as the cookie name, and any integer
in 'valid' is the number of seconds the cookie should
be valid"""
UserDict.UserDict.__init__(self)
if(identifier):
self.identifier = identifier
else:
try:
self.identifier = os.environ['HTTP_HOST']
except:
self.identifier = "localhost"
self.cookie = Cookie.SimpleCookie()
try:
self.cookie.load(os.environ['HTTP_COOKIE'])
self.id = self.cookie[self.identifier].value
self.data = pickle.load(open('/tmp/py_session_' +
self.identifier + '_' + self.id))
except: # Any kind of error forces a new session!
self.new_id()
self.new_session()
if(valid):
self.cookie[self.identifier]['expires'] = valid
print self.cookie.output()
def __del__(self):
pickle.dump(self.data,
open('/tmp/py_session_' + self.identifier +
'_' + self.id, 'w'))
def new_id(self):
"""Forces a new session id"""
choices = range(32,127) # the normal 7-bits ascii letters
key = ''
for char in range(20): # 20 chars, aprox 2**128 bits resolution
key = key + chr(random.choice(choices))
self.id = key
self.cookie[self.identifier] = self.id
def new_session(self):
"""Forces a blank session (reuse ID)"""
self.data = {}
|