summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 79c75de)
raw | patch | inline | side by side (parent: 79c75de)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Tue, 30 Jul 2002 08:22:38 +0000 (08:22 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Tue, 30 Jul 2002 08:22:38 +0000 (08:22 +0000) |
a simple anydbm wrapper now - which could be overridden by the metakit
backend or RDB backend if necessary.
Much, much better.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@932 57a73879-2fb5-44c3-a270-3262357dd7e2
backend or RDB backend if necessary.
Much, much better.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@932 57a73879-2fb5-44c3-a270-3262357dd7e2
roundup/backends/back_anydbm.py | patch | blob | history | |
roundup/backends/back_metakit.py | patch | blob | history | |
roundup/backends/sessions.py | [new file with mode: 0644] | patch | blob |
roundup/cgi_client.py | patch | blob | history |
index 3b85d788a954f1b3023b9b93a533d781d2e68007..e27344772d11724afde9bc06ea21ebdd9b72b8b0 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-#$Id: back_anydbm.py,v 1.54 2002-07-26 08:26:59 richard Exp $
+#$Id: back_anydbm.py,v 1.55 2002-07-30 08:22:38 richard Exp $
'''
This module defines a backend that saves the hyperdatabase in a database
chosen by anydbm. It is guaranteed to always be available in python
import whichdb, anydbm, os, marshal, re, weakref, string, copy
from roundup import hyperdb, date, password, roundupdb, security
from blobfiles import FileStorage
+from sessions import Sessions
from roundup.indexer import Indexer
from locking import acquire_lock, release_lock
from roundup.hyperdb import String, Password, Date, Interval, Link, \
self.destroyednodes = {}# keep track of the destroyed nodes by class
self.transactions = []
self.indexer = Indexer(self.dir)
+ self.sessions = Sessions(self.config)
self.security = security.Security(self)
# ensure files are group readable and writable
os.umask(0002)
#
#$Log: not supported by cvs2svn $
+#Revision 1.54 2002/07/26 08:26:59 richard
+#Very close now. The cgi and mailgw now use the new security API. The two
+#templates have been migrated to that setup. Lots of unit tests. Still some
+#issue in the web form for editing Roles assigned to users.
+#
#Revision 1.53 2002/07/25 07:14:06 richard
#Bugger it. Here's the current shape of the new security implementation.
#Still to do:
index a043e5a3d4cdeb77b307e3f3f16ec9387a80bd1f..b4065b0592a918f25fd474d97a2676fc9dad1705 100755 (executable)
-from roundup import hyperdb, date, password, roundupdb
+from roundup import hyperdb, date, password, roundupdb, security
import metakit
+from sessions import Sessions
import re, marshal, os, sys, weakref, time, calendar
from roundup import indexer
self.dirty = 0
self._db = self.__open()
self.indexer = Indexer(self.config.DATABASE, self._db)
+ self.sessions = Sessions(self.config)
+ self.security = security.Security(self)
+
os.umask(0002)
def post_init(self):
if self.indexer.should_reindex():
self.reindex()
def reindex(self):
- print "Reindexing!!!"
for klass in self.classes.values():
for nodeid in klass.list():
klass.index(nodeid)
diff --git a/roundup/backends/sessions.py b/roundup/backends/sessions.py
--- /dev/null
@@ -0,0 +1,101 @@
+#$Id: sessions.py,v 1.1 2002-07-30 08:22:38 richard Exp $
+'''
+This module defines a very basic store that's used by the CGI interface
+to store session information.
+'''
+
+import anydbm, whichdb, os, marshal
+
+class Sessions:
+ ''' Back onto an anydbm store.
+
+ Keys are session id strings, values are marshalled data.
+ '''
+ def __init__(self, config):
+ self.config = config
+ self.dir = config.DATABASE
+ # ensure files are group readable and writable
+ os.umask(0002)
+
+ def clear(self):
+ path = os.path.join(self.dir, 'sessions')
+ if os.path.exists(path):
+ os.remove(path)
+ elif os.path.exists(path+'.db'): # dbm appends .db
+ os.remove(path+'.db')
+
+ def determine_db_type(self, path):
+ ''' determine which DB wrote the class file
+ '''
+ db_type = ''
+ if os.path.exists(path):
+ db_type = whichdb.whichdb(path)
+ if not db_type:
+ raise hyperdb.DatabaseError, "Couldn't identify database type"
+ elif os.path.exists(path+'.db'):
+ # if the path ends in '.db', it's a dbm database, whether
+ # anydbm says it's dbhash or not!
+ db_type = 'dbm'
+ return db_type
+
+ def get(self, sessionid, value):
+ db = self.opendb('c')
+ try:
+ if db.has_key(sessionid):
+ values = marshal.loads(db[sessionid])
+ else:
+ return None
+ return values.get(value, None)
+ finally:
+ db.close()
+
+ def set(self, sessionid, **newvalues):
+ db = self.opendb('c')
+ try:
+ if db.has_key(sessionid):
+ values = marshal.loads(db[sessionid])
+ else:
+ values = {}
+ values.update(newvalues)
+ db[sessionid] = marshal.dumps(values)
+ finally:
+ db.close()
+
+ def list(self):
+ db = self.opendb('r')
+ try:
+ return db.keys()
+ finally:
+ db.close()
+
+ def destroy(self, sessionid):
+ db = self.opendb('c')
+ try:
+ if db.has_key(sessionid):
+ del db[sessionid]
+ finally:
+ db.close()
+
+ def opendb(self, mode):
+ '''Low-level database opener that gets around anydbm/dbm
+ eccentricities.
+ '''
+ # figure the class db type
+ path = os.path.join(os.getcwd(), self.dir, 'sessions')
+ db_type = self.determine_db_type(path)
+
+ # new database? let anydbm pick the best dbm
+ if not db_type:
+ return anydbm.open(path, 'n')
+
+ # open the database with the correct module
+ dbm = __import__(db_type)
+ return dbm.open(path, mode)
+
+ def commit(self):
+ pass
+
+#
+#$Log: not supported by cvs2svn $
+#
+#
diff --git a/roundup/cgi_client.py b/roundup/cgi_client.py
index f9fcd4048a76b47dcac53528556984f361f7fc20..9e0af6b1b2b903c48ec5a255d8d66283b4f467e3 100644 (file)
--- a/roundup/cgi_client.py
+++ b/roundup/cgi_client.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: cgi_client.py,v 1.146 2002-07-30 05:27:30 richard Exp $
+# $Id: cgi_client.py,v 1.147 2002-07-30 08:22:38 richard Exp $
__doc__ = """
WWW request handler (also used in the stand-alone server).
self.write('</table>')
self.pagefoot()
+ def unauthorised(self, message):
+ ''' The user is not authorised to do something. If they're
+ anonymous, throw up a login box. If not, just tell them they
+ can't do whatever it was they were trying to do.
+
+ Bot cases print up the message, which is most likely the
+ argument to the Unauthorised exception.
+ '''
+ self.header(response=403)
+ if self.desired_action is None or self.desired_action == 'login':
+ if not message:
+ message=_("You do not have permission.")
+ action = 'index'
+ else:
+ if not message:
+ message=_("You do not have permission to access"\
+ " %(action)s.")%{'action': self.desired_action}
+ action = self.desired_action
+ if self.user == 'anonymous':
+ self.login(action=action, message=message)
+ else:
+ self.pagehead(_('Not Authorised'))
+ self.write('<p class="system-msg">%s</p>'%message)
+ self.pagefoot()
+
def login(self, message=None, newuser_form=None, action='index'):
'''Display a login page.
'''
def set_cookie(self, user, password):
# TODO generate a much, much stronger session key ;)
- session = binascii.b2a_base64(repr(time.time())).strip()
+ self.session = binascii.b2a_base64(repr(time.time())).strip()
# clean up the base64
- if session[-1] == '=':
- if session[-2] == '=':
- session = session[:-2]
- else:
- session = session[:-1]
+ if self.session[-1] == '=':
+ if self.session[-2] == '=':
+ self.session = self.session[:-2]
+ else:
+ self.session = self.session[:-1]
# insert the session in the sessiondb
- sessions = self.db.getclass('__sessions')
- self.session = sessions.create(sessid=session, user=user,
- last_use=date.Date())
+ self.db.sessions.set(self.session, user=user, last_use=time.time())
# and commit immediately
self.db.commit()
path = '/'.join((self.env['SCRIPT_NAME'], self.env['INSTANCE_NAME'],
''))
self.header({'Set-Cookie': 'roundup_user=%s; expires=%s; Path=%s;'%(
- session, expire, path)})
+ self.session, expire, path)})
def make_user_anonymous(self):
- ''' Make use anonymous
+ ''' Make us anonymous
This method used to handle non-existence of the 'anonymous'
user, but that user is mandatory now.
self.user = 'anonymous'
def logout(self, message=None):
+ ''' Make us really anonymous - nuke the cookie too
+ '''
self.make_user_anonymous()
+
# construct the logout cookie
now = Cookie._getdate()
path = '/'.join((self.env['SCRIPT_NAME'], self.env['INSTANCE_NAME'],
# open the db
self.db = self.instance.open(user)
- # make sure we have the session Class
- try:
- sessions = self.db.getclass('__sessions')
- except:
- # add the sessions Class - use a non-journalling Class
- # TODO: not happy with how we're getting the Class here :(
- sessions = self.instance.dbinit.Class(self.db, '__sessions',
- sessid=hyperdb.String(), user=hyperdb.String(),
- last_use=hyperdb.Date())
- sessions.setkey('sessid')
- # make sure session db isn't journalled
- sessions.disableJournalling()
-
def main(self):
''' Wrap the request and handle unauthorised requests
'''
try:
self.main_action()
except Unauthorised, message:
- self.header(response=403)
- if self.desired_action is None or self.desired_action == 'login':
- if not message:
- message=_("You do not have permission.")
- # go to the index after login
- self.login(message=message)
- else:
- if not message:
- message=_("You do not have permission to access"\
- " %(action)s.")%{'action': self.desired_action}
- self.login(action=self.desired_action, message=message)
+ self.unauthorised(message)
def main_action(self):
'''Wrap the database accesses so we can close the database cleanly
self.opendb('admin')
# make sure we have the session Class
- sessions = self.db.getclass('__sessions')
+ sessions = self.db.sessions
# age sessions, remove when they haven't been used for a week
# TODO: this shouldn't be done every access
- week = date.Interval('7d')
- now = date.Date()
+ week = 60*60*24*7
+ now = time.time()
for sessid in sessions.list():
interval = now - sessions.get(sessid, 'last_use')
if interval > week:
# look up the user session cookie
cookie = Cookie.Cookie(self.env.get('HTTP_COOKIE', ''))
user = 'anonymous'
+
if (cookie.has_key('roundup_user') and
cookie['roundup_user'].value != 'deleted'):
# get the session key from the cookie
- session = cookie['roundup_user'].value
+ self.session = cookie['roundup_user'].value
# get the user from the session
try:
- self.session = sessions.lookup(session)
+ # update the lifetime datestamp
+ sessions.set(self.session, last_use=time.time())
+ sessions.commit()
+ user = sessions.get(self.session, 'user')
except KeyError:
user = 'anonymous'
- else:
- # update the lifetime datestamp
- sessions.set(self.session, last_use=date.Date())
- self.db.commit()
- user = sessions.get(sessid, 'user')
# sanity check on the user still being valid
try:
#
# $Log: not supported by cvs2svn $
+# Revision 1.146 2002/07/30 05:27:30 richard
+# nicer error messages, and a bugfix
+#
# Revision 1.145 2002/07/26 08:26:59 richard
# Very close now. The cgi and mailgw now use the new security API. The two
# templates have been migrated to that setup. Lots of unit tests. Still some