Code

- fixed bug in login if the username wasn't known
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 27 Sep 2002 01:04:38 +0000 (01:04 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 27 Sep 2002 01:04:38 +0000 (01:04 +0000)
- 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
doc/customizing.txt
roundup/backends/back_sqlite.py
roundup/cgi/client.py

index d70de865e02bc4de1a27b9730b9f461677cdb0d5..f60040a0e73aa79a8878bdb14842f5dad658010f 100644 (file)
@@ -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
index d15973f3e77bec47135acc108299a7389685ede7..55d7acba758a240a37b15252600d5dad8eaff1c1 100644 (file)
@@ -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`_
index 2265db6b950781f6242de9003f5f3999e95bbe49..cbd6d6e6200197c619713ac377506fcffec867e8 100644 (file)
@@ -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 '<roundlite 0x%x>'%id(self)
 
index 1c5ecd114388aed524ba7482c6a813a0194be750..7d0e67261dfbf8a91d2c6ce38b654fd37e246475 100644 (file)
@@ -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)