Revision: 8174
          http://svn.sourceforge.net/mailman/?rev=8174&view=rev
Author:   bwarsaw
Date:     2007-03-21 21:29:31 -0700 (Wed, 21 Mar 2007)

Log Message:
-----------
Restore the use of passwords.Schemes enum for selection of password hashing
scheme.  Fix mmsitepass and test cases accordingly.  Details:

- set_global_password(): Instead of taking a string for 'scheme' argument,
  take None and then coerce that into passwords.Schemes.ssha

- Add a base PasswordError and a BadPasswordSchemeError error that derives
  from that.  For consistency, multiply inherit MMBadPasswordError and
  MMPasswordsMustMatch from PasswordError.

- Add a passwords.lookup_scheme() method which turns scheme_names into scheme
  enum constants.  It returns None if the lookup fails.

- passwords.py: change the internal representation of _SCHEMES_BY_TAG
  dictionary to map scheme names to scheme enum values.  Change internal uses
  of this dictionary to then turn those enum values into hash classes, or
  whatever else we need.

- make_secret(): Raise BadPasswordSchemeErrorif the given schema (which should
  be an enum value) is invalid.

- TestBase.tearDown(): Clear out any <site> locks that might hang around after
  a test case runs.

Modified Paths:
--------------
    trunk/mailman/Mailman/Errors.py
    trunk/mailman/Mailman/Utils.py
    trunk/mailman/Mailman/bin/mmsitepass.py
    trunk/mailman/Mailman/passwords.py
    trunk/mailman/Mailman/testing/base.py
    trunk/mailman/Mailman/testing/test_handlers.py
    trunk/mailman/Mailman/testing/test_membership.py
    trunk/mailman/Mailman/testing/test_passwords.py
    trunk/mailman/Mailman/testing/test_security_mgr.py

Modified: trunk/mailman/Mailman/Errors.py
===================================================================
--- trunk/mailman/Mailman/Errors.py     2007-03-21 21:31:59 UTC (rev 8173)
+++ trunk/mailman/Mailman/Errors.py     2007-03-22 04:29:31 UTC (rev 8174)
@@ -58,8 +58,6 @@
 # Exception hierarchy for various authentication failures, can be
 # raised from functions in SecurityManager.py
 class MMAuthenticationError(MailmanException): pass
-class MMBadPasswordError(MMAuthenticationError): pass
-class MMPasswordsMustMatch(MMAuthenticationError): pass
 class MMCookieError(MMAuthenticationError): pass
 class MMExpiredCookieError(MMCookieError): pass
 class MMInvalidCookieError(MMCookieError): pass
@@ -191,3 +189,26 @@
         from Mailman.Version import DATABASE_SCHEMA_VERSION
         return 'Incompatible database schema version (got: %d, expected: %d)' \
                % (self._got, DATABASE_SCHEMA_VERSION)
+
+
+
+class PasswordError(MailmanError):
+    """A password related error."""
+
+
+class MMBadPasswordError(PasswordError, MMAuthenticationError):
+    """A bad password was given."""
+
+
+class MMPasswordsMustMatch(PasswordError, MMAuthenticationError):
+    """The given passwords don't match."""
+
+
+class BadPasswordSchemeError(PasswordError):
+    """A bad password scheme was given."""
+
+    def __init__(self, scheme_name='unknown'):
+        self.scheme_name = scheme_name
+
+    def __str__(self):
+        return 'A bad password scheme was given: %s' % self.scheme_name

Modified: trunk/mailman/Mailman/Utils.py
===================================================================
--- trunk/mailman/Mailman/Utils.py      2007-03-21 21:31:59 UTC (rev 8173)
+++ trunk/mailman/Mailman/Utils.py      2007-03-22 04:29:31 UTC (rev 8174)
@@ -335,7 +335,9 @@
 
 
 
-def set_global_password(pw, siteadmin=True, scheme='ssha'):
+def set_global_password(pw, siteadmin=True, scheme=None):
+    if scheme is None:
+        scheme = passwords.Schemes.ssha
     if siteadmin:
         filename = config.SITE_PW_FILE
     else:

Modified: trunk/mailman/Mailman/bin/mmsitepass.py
===================================================================
--- trunk/mailman/Mailman/bin/mmsitepass.py     2007-03-21 21:31:59 UTC (rev 
8173)
+++ trunk/mailman/Mailman/bin/mmsitepass.py     2007-03-22 04:29:31 UTC (rev 
8174)
@@ -68,7 +68,7 @@
         parser.error(_('Unexpected arguments'))
     if opts.list_hash_schemes:
         for label in passwords.Schemes:
-            print label.upper()
+            print str(label).upper()
         sys.exit(0)
     return parser, opts, args
 
@@ -77,9 +77,10 @@
     # shoule be checked after config is loaded.
     if password_scheme == '':
         password_scheme = config.PASSWORD_SCHEME
-    if password_scheme.lower() not in passwords.Schemes:
+    scheme = passwords.lookup_scheme(password_scheme.lower())
+    if not scheme:
         parser.error(_('Invalid password scheme'))
-    return password_scheme
+    return scheme
 
 
 

Modified: trunk/mailman/Mailman/passwords.py
===================================================================
--- trunk/mailman/Mailman/passwords.py  2007-03-21 21:31:59 UTC (rev 8173)
+++ trunk/mailman/Mailman/passwords.py  2007-03-22 04:29:31 UTC (rev 8174)
@@ -29,6 +29,7 @@
 from base64 import urlsafe_b64decode as decode
 from base64 import urlsafe_b64encode as encode
 
+from Mailman import Errors
 from Mailman.enum import Enum
 
 SALT_LENGTH = 20 # bytes
@@ -202,8 +203,8 @@
 
 # Some scheme tags have arguments, but the key for this dictionary should just
 # be the lowercased scheme name.
-_SCHEMES_BY_TAG = dict((c.TAG.split(' ')[0].lower(), c)
-                       for c in _SCHEMES_BY_ENUM.values())
+_SCHEMES_BY_TAG = dict((_SCHEMES_BY_ENUM[e].TAG.split(' ')[0].lower(), e)
+                       for e in _SCHEMES_BY_ENUM)
 
 _DEFAULT_SCHEME = NoPasswordScheme
 
@@ -218,7 +219,9 @@
     # be a unicode.
     if isinstance(password, unicode):
         password = password.encode('utf-8')
-    scheme_class = _SCHEMES_BY_TAG.get(scheme, _DEFAULT_SCHEME)
+    scheme_class = _SCHEMES_BY_ENUM.get(scheme)
+    if not scheme_class:
+        raise Errors.BadPasswordSchemeError(scheme)
     secret = scheme_class.make_secret(password)
     return '{%s}%s' % (scheme_class.TAG, secret)
 
@@ -235,8 +238,10 @@
     scheme_group, rest_group = mo.group('scheme', 'rest')
     scheme_parts = scheme_group.split()
     scheme       = scheme_parts[0].lower()
-    scheme_class = _SCHEMES_BY_TAG.get(scheme, _DEFAULT_SCHEME)
-    if isinstance(rest_group, unicode):
-        # decode() fails. (challenge is from database)
-        rest_group = str(rest_group)
+    scheme_enum  = _SCHEMES_BY_TAG.get(scheme, _DEFAULT_SCHEME)
+    scheme_class = _SCHEMES_BY_ENUM[scheme_enum]
     return scheme_class.check_response(rest_group, response, *scheme_parts[1:])
+
+
+def lookup_scheme(scheme_name):
+    return _SCHEMES_BY_TAG.get(scheme_name.lower())

Modified: trunk/mailman/Mailman/testing/base.py
===================================================================
--- trunk/mailman/Mailman/testing/base.py       2007-03-21 21:31:59 UTC (rev 
8173)
+++ trunk/mailman/Mailman/testing/base.py       2007-03-22 04:29:31 UTC (rev 
8174)
@@ -118,3 +118,9 @@
                            archives=True, quiet=True)
         os.unlink(self._config)
         os.unlink(self._dbfile)
+        # Clear out any site locks, which can be left over if tests fail.
+        for filename in os.listdir(config.LOCK_DIR):
+            if filename.startswith('<site>'):
+                path = os.path.join(config.LOCK_DIR, filename)
+                print >> sys.stderr, '@@@@@ removing:', path
+                os.unlink(path)

Modified: trunk/mailman/Mailman/testing/test_handlers.py
===================================================================
--- trunk/mailman/Mailman/testing/test_handlers.py      2007-03-21 21:31:59 UTC 
(rev 8173)
+++ trunk/mailman/Mailman/testing/test_handlers.py      2007-03-22 04:29:31 UTC 
(rev 8174)
@@ -59,7 +59,7 @@
 
 
 def password(cleartext):
-    return passwords.make_secret(cleartext, 'ssha')
+    return passwords.make_secret(cleartext, passwords.Schemes.ssha)
 
 
 

Modified: trunk/mailman/Mailman/testing/test_membership.py
===================================================================
--- trunk/mailman/Mailman/testing/test_membership.py    2007-03-21 21:31:59 UTC 
(rev 8173)
+++ trunk/mailman/Mailman/testing/test_membership.py    2007-03-22 04:29:31 UTC 
(rev 8174)
@@ -33,7 +33,7 @@
 
 
 def password(cleartext):
-    return passwords.make_secret(cleartext, 'ssha')
+    return passwords.make_secret(cleartext, passwords.Schemes.ssha)
 
 
 

Modified: trunk/mailman/Mailman/testing/test_passwords.py
===================================================================
--- trunk/mailman/Mailman/testing/test_passwords.py     2007-03-21 21:31:59 UTC 
(rev 8173)
+++ trunk/mailman/Mailman/testing/test_passwords.py     2007-03-22 04:29:31 UTC 
(rev 8174)
@@ -19,6 +19,7 @@
 
 import unittest
 
+from Mailman import Errors
 from Mailman import passwords
 
 
@@ -72,6 +73,27 @@
     scheme = -1
 
     def test_passwords(self):
+        self.assertRaises(Errors.BadPasswordSchemeError,
+                          passwords.make_secret, self.pw8a, self.scheme)
+
+    def test_unicode_passwords(self):
+        self.assertRaises(Errors.BadPasswordSchemeError,
+                          passwords.make_secret, self.pwua, self.scheme)
+
+    def test_passwords_with_funky_chars(self):
+        self.assertRaises(Errors.BadPasswordSchemeError,
+                          passwords.make_secret, self.pw8b, self.scheme)
+
+    def test_unicode_passwords_with_funky_chars(self):
+        self.assertRaises(Errors.BadPasswordSchemeError,
+                          passwords.make_secret, self.pwub, self.scheme)
+
+
+
+class TestNonePasswords(TestPasswordsBase):
+    scheme = passwords.Schemes.no_scheme
+
+    def test_passwords(self):
         failif = self.failIf
         secret = passwords.make_secret(self.pw8a, self.scheme)
         failif(passwords.check_response(secret, self.pw8a))
@@ -97,27 +119,36 @@
 
 
 
-class TestNonePasswords(TestBogusPasswords):
-    scheme = 'no_scheme'
-
-
 class TestCleartextPasswords(TestPasswordsBase):
-    scheme = 'cleartext'
+    scheme = passwords.Schemes.cleartext
 
 
 class TestSHAPasswords(TestPasswordsBase):
-    scheme = 'sha'
+    scheme = passwords.Schemes.sha
 
 
 class TestSSHAPasswords(TestPasswordsBase):
-    scheme = 'ssha'
+    scheme = passwords.Schemes.ssha
 
 
 class TestPBKDF2Passwords(TestPasswordsBase):
-    scheme = 'pbkdf2'
+    scheme = passwords.Schemes.pbkdf2
 
 
 
+class TestSchemeLookup(unittest.TestCase):
+    def test_scheme_name_lookup(self):
+        unless = self.failUnless
+        unless(passwords.lookup_scheme('NONE') is passwords.Schemes.no_scheme)
+        unless(passwords.lookup_scheme('CLEARTEXT') is
+               passwords.Schemes.cleartext)
+        unless(passwords.lookup_scheme('SHA') is passwords.Schemes.sha)
+        unless(passwords.lookup_scheme('SSHA') is passwords.Schemes.ssha)
+        unless(passwords.lookup_scheme('PBKDF2') is passwords.Schemes.pbkdf2)
+        unless(passwords.lookup_scheme(' -bogus- ') is None)
+
+
+
 def test_suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(TestBogusPasswords))
@@ -126,4 +157,5 @@
     suite.addTest(unittest.makeSuite(TestSHAPasswords))
     suite.addTest(unittest.makeSuite(TestSSHAPasswords))
     suite.addTest(unittest.makeSuite(TestPBKDF2Passwords))
+    suite.addTest(unittest.makeSuite(TestSchemeLookup))
     return suite

Modified: trunk/mailman/Mailman/testing/test_security_mgr.py
===================================================================
--- trunk/mailman/Mailman/testing/test_security_mgr.py  2007-03-21 21:31:59 UTC 
(rev 8173)
+++ trunk/mailman/Mailman/testing/test_security_mgr.py  2007-03-22 04:29:31 UTC 
(rev 8174)
@@ -36,7 +36,7 @@
 
 
 def password(cleartext):
-    return passwords.make_secret(cleartext, 'ssha')
+    return passwords.make_secret(cleartext, passwords.Schemes.ssha)
 
 
 


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe: 
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org

Reply via email to