From 058af6c75519ac00eca3ca01174ce0a180f6e270 Mon Sep 17 00:00:00 2001 From: richard Date: Fri, 27 Sep 2002 01:04:38 +0000 Subject: [PATCH] - fixed bug in login if the username wasn't known - handle close/rollback of already-closed sqlite database - added example for external passwd-style user password verification git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1274 57a73879-2fb5-44c3-a270-3262357dd7e2 --- CHANGES.txt | 1 + doc/customizing.txt | 41 ++++++++++++++++++++++++++++++++- roundup/backends/back_sqlite.py | 41 ++++++++++++++++++++++++++++++++- roundup/cgi/client.py | 12 ++++++---- 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index d70de86..f60040a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -46,6 +46,7 @@ are given with the most recent entry first. - fixed the mailgw so that anonymous users may still access it - add hook to allow external password verification, overridable in the tracker interfaces module +- fixed login attempt by user that doesn't exist 2002-09-13 0.5.0 beta2 - all backends now have a .close() method, and it's used everywhere diff --git a/doc/customizing.txt b/doc/customizing.txt index d15973f..55d7acb 100644 --- a/doc/customizing.txt +++ b/doc/customizing.txt @@ -2,7 +2,7 @@ Customising Roundup =================== -:Version: $Revision: 1.49 $ +:Version: $Revision: 1.50 $ .. This document borrows from the ZopeBook section on ZPT. The original is at: http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx @@ -2118,6 +2118,45 @@ Setting up a "wizard" (or "druid") for controlled adding of issues 4. Use the usual "new" action as the :action on the final page, and you're done (the standard context/submit method can do this for you). + +Using an external password validation source +-------------------------------------------- + +We have a centrally-managed password changing system for our users. This +results in a UN*X passwd-style file that we use for verification of users. +Entries in the file consist of ``name:password`` where the password is +encrypted using the standard UN*X ``crypt()`` function (see the ``crypt`` +module in your Python distribution). An example entry would be:: + + admin:aamrgyQfDFSHw + +Each user of Roundup must still have their information stored in the Roundup +database - we just use the passwd file to check their password. To do this, we +add the following code to our ``Client`` class in the tracker home +``interfaces.py`` module:: + + def verifyPassword(self, userid, password): + # get the user's username + username = self.db.user.get(userid, 'username') + + # the passwords are stored in the "passwd.txt" file in the tracker + # home + file = os.path.join(self.db.config.TRACKER_HOME, 'passwd.txt') + + # see if we can find a match + for ent in [line.strip().split(':') for line in open(file).readlines()]: + if ent[0] == username: + return crypt.crypt(password, ent[1][:2]) == ent[1] + + # user doesn't exist in the file + return 0 + +What this does is look through the file, line by line, looking for a name that +matches. + +We also remove the redundant password fields from the ``user.item`` template. + + ------------------- Back to `Table of Contents`_ diff --git a/roundup/backends/back_sqlite.py b/roundup/backends/back_sqlite.py index 2265db6..cbd6d6e 100644 --- a/roundup/backends/back_sqlite.py +++ b/roundup/backends/back_sqlite.py @@ -1,4 +1,4 @@ -# $Id: back_sqlite.py,v 1.5 2002-09-24 01:59:28 richard Exp $ +# $Id: back_sqlite.py,v 1.6 2002-09-27 01:04:38 richard Exp $ __doc__ = ''' See https://pysqlite.sourceforge.net/ for pysqlite info ''' @@ -25,6 +25,45 @@ class Database(Database): self.cursor.execute('create table schema (schema varchar)') self.cursor.execute('create table ids (name varchar, num integer)') + def close(self): + ''' Close off the connection. + + Squash any error caused by us already having closed the + connection. + ''' + try: + self.conn.close() + except sqlite.ProgrammingError, value: + if str(value) != 'close failed - Connection is closed.': + raise + + + def rollback(self): + ''' Reverse all actions from the current transaction. + + Undo all the changes made since the database was opened or the + last commit() or rollback() was performed. + + Squash any error caused by us having closed the connection (and + therefore not having anything to roll back) + ''' + if __debug__: + print >>hyperdb.DEBUG, 'rollback', (self,) + + # roll back + try: + self.conn.rollback() + except sqlite.ProgrammingError, value: + if str(value) != 'rollback failed - Connection is closed.': + raise + + # roll back "other" transaction stuff + for method, args in self.transactions: + # delete temporary files + if method == self.doStoreFile: + self.rollbackStoreFile(*args) + self.transactions = [] + def __repr__(self): return ''%id(self) diff --git a/roundup/cgi/client.py b/roundup/cgi/client.py index 1c5ecd1..7d0e672 100644 --- a/roundup/cgi/client.py +++ b/roundup/cgi/client.py @@ -1,4 +1,4 @@ -# $Id: client.py,v 1.47 2002-09-26 23:59:08 richard Exp $ +# $Id: client.py,v 1.48 2002-09-27 01:04:38 richard Exp $ __doc__ = """ WWW request handler (also used in the stand-alone server). @@ -485,22 +485,23 @@ class Client: self.error_message.append(_('Username required')) return + # get the login info self.user = self.form['__login_name'].value - # re-open the database for real, using the user - self.opendb(self.user) if self.form.has_key('__login_password'): password = self.form['__login_password'].value else: password = '' + # make sure the user exists try: self.userid = self.db.user.lookup(self.user) except KeyError: name = self.user - self.make_user_anonymous() self.error_message.append(_('No such user "%(name)s"')%locals()) + self.make_user_anonymous() return + # verify the password if not self.verifyPassword(self.userid, password): self.make_user_anonymous() self.error_message.append(_('Incorrect password')) @@ -511,6 +512,9 @@ class Client: self.make_user_anonymous() raise Unauthorised, _("You do not have permission to login") + # now we're OK, re-open the database for real, using the user + self.opendb(self.user) + # set the session cookie self.set_cookie(self.user) -- 2.30.2