Skip to content

Commit d2cb415

Browse files
author
Richard Jones
committed
switched to using a session-based web login
1 parent f5bb585 commit d2cb415

File tree

1 file changed

+88
-46
lines changed

1 file changed

+88
-46
lines changed

roundup/cgi_client.py

Lines changed: 88 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: cgi_client.py,v 1.134 2002-07-09 04:19:09 richard Exp $
18+
# $Id: cgi_client.py,v 1.135 2002-07-10 00:22:34 richard Exp $
1919

2020
__doc__ = """
2121
WWW request handler (also used in the stand-alone server).
@@ -112,7 +112,7 @@ def header(self, headers=None):
112112
}
113113
114114
function help_window(helpurl, width, height) {
115-
HelpWin = window.open('%(base)s%(instance_path_name)s/' + helpurl, 'HelpWindow', 'scrollbars=yes,resizable=yes,toolbar=no,height='+height+',width='+width);
115+
HelpWin = window.open('%(base)s%(instance_path_name)s/' + helpurl, 'RoundupHelpWindow', 'scrollbars=yes,resizable=yes,toolbar=no,height='+height+',width='+width);
116116
}
117117
118118
</script>
@@ -431,21 +431,6 @@ def index(self):
431431
def searchnode(self):
432432
columns, filter, group, sort, filterspec, pagesize = \
433433
self._get_customisation_info()
434-
## show_nodes = 1
435-
## if len(self.form.keys()) == 0:
436-
## # get the default search filters from instance_config
437-
## if hasattr(self.instance, 'SEARCH_FILTERS'):
438-
## for f in self.instance.SEARCH_FILTERS:
439-
## spec = getattr(self.instance, f)
440-
## if spec['CLASS'] == self.classname:
441-
## filter = spec['FILTER']
442-
##
443-
## show_nodes = 0
444-
## show_customization = 1
445-
## return self.list(columns=columns, filter=filter, group=group,
446-
## sort=sort, filterspec=filterspec,
447-
## show_customization=show_customization, show_nodes=show_nodes,
448-
## pagesize=pagesize)
449434
cn = self.classname
450435
self.pagehead(_('%(instancename)s: Index of %(classname)s')%{
451436
'classname': cn, 'instancename': self.instance.INSTANCE_NAME})
@@ -665,7 +650,8 @@ def shownode(self, message=None, num_re=re.compile('^\d+$')):
665650
id = self.nodeid
666651
if cl.getkey():
667652
id = cl.get(id, cl.getkey())
668-
self.pagehead('%s: %s %s'%(self.classname.capitalize(), id, xtra), message)
653+
self.pagehead('%s: %s %s'%(self.classname.capitalize(), id, xtra),
654+
message)
669655

670656
nodeid = self.nodeid
671657

@@ -1111,6 +1097,8 @@ def login_action(self, message=None):
11111097
self.login(message=_('Username required'))
11121098
return 0
11131099
self.user = self.form['__login_name'].value
1100+
# re-open the database for real, using the user
1101+
self.opendb(self.user)
11141102
if self.form.has_key('__login_password'):
11151103
password = self.form['__login_password'].value
11161104
else:
@@ -1144,7 +1132,7 @@ def newuser_action(self, message=None):
11441132
return 1 on successful login
11451133
'''
11461134
# re-open the database as "admin"
1147-
self.db = self.instance.open('admin')
1135+
self.opendb('admin')
11481136

11491137
# TODO: pre-check the required fields and username key property
11501138
cl = self.db.user
@@ -1156,22 +1144,42 @@ def newuser_action(self, message=None):
11561144
self.login(message, action=action)
11571145
return 0
11581146
self.user = cl.get(uid, 'username')
1147+
# re-open the database for real, using the user
1148+
self.opendb(self.user)
11591149
password = cl.get(uid, 'password')
11601150
self.set_cookie(self.user, self.form['password'].value)
11611151
return 1
11621152

11631153
def set_cookie(self, user, password):
1164-
# construct the cookie
1165-
user = binascii.b2a_base64('%s:%s'%(user, password)).strip()
1166-
if user[-1] == '=':
1167-
if user[-2] == '=':
1168-
user = user[:-2]
1154+
# TODO generate a much, much stronger session key ;)
1155+
session = binascii.b2a_base64(repr(time.time())).strip()
1156+
1157+
# clean up the base64
1158+
if session[-1] == '=':
1159+
if session[-2] == '=':
1160+
session = session[:-2]
11691161
else:
1170-
user = user[:-1]
1162+
session = session[:-1]
1163+
1164+
print 'session set to', `session`
1165+
1166+
# insert the session in the sessiondb
1167+
self.db.getclass('__sessions').create(sessid=session, user=user,
1168+
last_use=date.Date())
1169+
1170+
# and commit immediately
1171+
self.db.commit()
1172+
1173+
# expire us in a long, long time
1174+
# TODO: hrm, how long should this be, and how many sessions can one
1175+
# user have?
11711176
expire = Cookie._getdate(86400*365)
1172-
path = '/'.join((self.env['SCRIPT_NAME'], self.env['INSTANCE_NAME']))
1173-
self.header({'Set-Cookie': 'roundup_user=%s; expires=%s; Path=%s;' % (
1174-
user, expire, path)})
1177+
1178+
# generate the cookie path - make sure it has a trailing '/'
1179+
path = '/'.join((self.env['SCRIPT_NAME'], self.env['INSTANCE_NAME'],
1180+
''))
1181+
self.header({'Set-Cookie': 'roundup_user=%s; expires=%s; Path=%s;'%(
1182+
session, expire, path)})
11751183

11761184
def make_user_anonymous(self):
11771185
# make us anonymous if we can
@@ -1185,48 +1193,74 @@ def logout(self, message=None):
11851193
self.make_user_anonymous()
11861194
# construct the logout cookie
11871195
now = Cookie._getdate()
1188-
path = '/'.join((self.env['SCRIPT_NAME'], self.env['INSTANCE_NAME']))
1196+
path = '/'.join((self.env['SCRIPT_NAME'], self.env['INSTANCE_NAME'],
1197+
''))
11891198
self.header({'Set-Cookie':
11901199
'roundup_user=deleted; Max-Age=0; expires=%s; Path=%s;'%(now,
11911200
path)})
11921201
self.login()
11931202

1203+
def opendb(self, user):
1204+
''' Open the database - but include the definition of the sessions db.
1205+
'''
1206+
# open the db
1207+
self.db = self.instance.open(user)
1208+
1209+
# make sure we have the session Class
1210+
try:
1211+
sessions = self.db.getclass('__sessions')
1212+
except:
1213+
# add the sessions Class
1214+
sessions = hyperdb.Class(self.db, '__sessions',
1215+
sessid=hyperdb.String(), user=hyperdb.String(),
1216+
last_use=hyperdb.Date())
1217+
sessions.setkey('sessid')
1218+
11941219
def main(self):
11951220
'''Wrap the database accesses so we can close the database cleanly
11961221
'''
11971222
# determine the uid to use
1198-
self.db = self.instance.open('admin')
1223+
self.opendb('admin')
1224+
1225+
# make sure we have the session Class
1226+
sessions = self.db.getclass('__sessions')
1227+
1228+
# age sessions, remove when they haven't been used for a week
1229+
# TODO: this doesn't need to be done every access
1230+
week = date.Interval('7d')
1231+
now = date.Date()
1232+
for sessid in sessions.list():
1233+
interval = now - sessions.get(sessid, 'last_use')
1234+
if interval > week:
1235+
sessions.destroy(sessid)
1236+
1237+
# look up the user session cookie
11991238
cookie = Cookie.Cookie(self.env.get('HTTP_COOKIE', ''))
12001239
user = 'anonymous'
12011240
if (cookie.has_key('roundup_user') and
12021241
cookie['roundup_user'].value != 'deleted'):
1203-
cookie = cookie['roundup_user'].value
1204-
if len(cookie)%4:
1205-
cookie = cookie + '='*(4-len(cookie)%4)
1206-
try:
1207-
user, password = binascii.a2b_base64(cookie).split(':')
1208-
except (TypeError, binascii.Error, binascii.Incomplete):
1209-
# damaged cookie!
1210-
user, password = 'anonymous', ''
1242+
print cookie
1243+
1244+
# get the session key from the cookie
1245+
session = cookie['roundup_user'].value
1246+
print 'session is', `session`
12111247

1212-
# make sure the user exists
1248+
# get the user from the session
12131249
try:
1214-
uid = self.db.user.lookup(user)
1215-
# now validate the password
1216-
if password != self.db.user.get(uid, 'password'):
1217-
user = 'anonymous'
1250+
sessid = sessions.lookup(session)
12181251
except KeyError:
12191252
user = 'anonymous'
1253+
else:
1254+
sessions.set(sessid, last_use=date.Date())
1255+
self.db.commit()
1256+
user = sessions.get(sessid, 'user')
12201257

12211258
# make sure the anonymous user is valid if we're using it
12221259
if user == 'anonymous':
12231260
self.make_user_anonymous()
12241261
else:
12251262
self.user = user
12261263

1227-
# re-open the database for real, using the user
1228-
self.db = self.instance.open(self.user)
1229-
12301264
# now figure which function to call
12311265
path = self.split_path
12321266

@@ -1279,6 +1313,9 @@ def main(self):
12791313
self.login(action=action)
12801314
return
12811315

1316+
# re-open the database for real, using the user
1317+
self.opendb(self.user)
1318+
12821319
# just a regular action
12831320
self.do_action(action)
12841321

@@ -1454,6 +1491,11 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
14541491

14551492
#
14561493
# $Log: not supported by cvs2svn $
1494+
# Revision 1.134 2002/07/09 04:19:09 richard
1495+
# Added reindex command to roundup-admin.
1496+
# Fixed reindex on first access.
1497+
# Also fixed reindexing of entries that change.
1498+
#
14571499
# Revision 1.133 2002/07/08 15:32:05 gmcm
14581500
# Pagination of index pages.
14591501
# New search form.

0 commit comments

Comments
 (0)