summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Errors.py25
-rw-r--r--Mailman/Utils.py4
-rw-r--r--Mailman/bin/mmsitepass.py7
-rw-r--r--Mailman/passwords.py19
-rw-r--r--Mailman/testing/base.py6
-rw-r--r--Mailman/testing/test_handlers.py2
-rw-r--r--Mailman/testing/test_membership.py2
-rw-r--r--Mailman/testing/test_passwords.py48
-rw-r--r--Mailman/testing/test_security_mgr.py2
9 files changed, 91 insertions, 24 deletions
diff --git a/Mailman/Errors.py b/Mailman/Errors.py
index 2c1686fdb..10081f08d 100644
--- a/Mailman/Errors.py
+++ b/Mailman/Errors.py
@@ -58,8 +58,6 @@ class MembershipIsBanned(MemberError): pass
# 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 @@ class SchemaVersionMismatchError(DatabaseError):
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
diff --git a/Mailman/Utils.py b/Mailman/Utils.py
index 958a3e959..afb2f1fd5 100644
--- a/Mailman/Utils.py
+++ b/Mailman/Utils.py
@@ -335,7 +335,9 @@ def GetRandomSeed():
-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:
diff --git a/Mailman/bin/mmsitepass.py b/Mailman/bin/mmsitepass.py
index 0246856bd..c8b0d27ec 100644
--- a/Mailman/bin/mmsitepass.py
+++ b/Mailman/bin/mmsitepass.py
@@ -68,7 +68,7 @@ case-insensitive."""))
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 @@ def check_password_scheme(parser, password_scheme):
# 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
diff --git a/Mailman/passwords.py b/Mailman/passwords.py
index 2b7d38f2d..a46c11a16 100644
--- a/Mailman/passwords.py
+++ b/Mailman/passwords.py
@@ -29,6 +29,7 @@ from array import array
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 @@ _SCHEMES_BY_ENUM = {
# 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 @@ def make_secret(password, scheme=None):
# 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 @@ def check_response(challenge, response):
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())
diff --git a/Mailman/testing/base.py b/Mailman/testing/base.py
index 2979ad18b..8a131175e 100644
--- a/Mailman/testing/base.py
+++ b/Mailman/testing/base.py
@@ -118,3 +118,9 @@ class TestBase(unittest.TestCase):
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)
diff --git a/Mailman/testing/test_handlers.py b/Mailman/testing/test_handlers.py
index 849ccfb91..b2fb5ce27 100644
--- a/Mailman/testing/test_handlers.py
+++ b/Mailman/testing/test_handlers.py
@@ -59,7 +59,7 @@ from Mailman.Handlers import ToUsenet
def password(cleartext):
- return passwords.make_secret(cleartext, 'ssha')
+ return passwords.make_secret(cleartext, passwords.Schemes.ssha)
diff --git a/Mailman/testing/test_membership.py b/Mailman/testing/test_membership.py
index ed8ebb1f4..8e8285034 100644
--- a/Mailman/testing/test_membership.py
+++ b/Mailman/testing/test_membership.py
@@ -33,7 +33,7 @@ from Mailman.testing.base import TestBase
def password(cleartext):
- return passwords.make_secret(cleartext, 'ssha')
+ return passwords.make_secret(cleartext, passwords.Schemes.ssha)
diff --git a/Mailman/testing/test_passwords.py b/Mailman/testing/test_passwords.py
index b957b10ae..8298c22f6 100644
--- a/Mailman/testing/test_passwords.py
+++ b/Mailman/testing/test_passwords.py
@@ -19,6 +19,7 @@
import unittest
+from Mailman import Errors
from Mailman import passwords
@@ -72,6 +73,27 @@ class TestBogusPasswords(TestPasswordsBase):
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,24 +119,33 @@ class TestBogusPasswords(TestPasswordsBase):
-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)
@@ -126,4 +157,5 @@ def test_suite():
suite.addTest(unittest.makeSuite(TestSHAPasswords))
suite.addTest(unittest.makeSuite(TestSSHAPasswords))
suite.addTest(unittest.makeSuite(TestPBKDF2Passwords))
+ suite.addTest(unittest.makeSuite(TestSchemeLookup))
return suite
diff --git a/Mailman/testing/test_security_mgr.py b/Mailman/testing/test_security_mgr.py
index 543330aed..089f4b0ef 100644
--- a/Mailman/testing/test_security_mgr.py
+++ b/Mailman/testing/test_security_mgr.py
@@ -36,7 +36,7 @@ from Mailman.testing.base import TestBase
def password(cleartext):
- return passwords.make_secret(cleartext, 'ssha')
+ return passwords.make_secret(cleartext, passwords.Schemes.ssha)