# Copyright (C) 2001-2010 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. """Unit tests for Mailman/SecurityManager.py """ import os import unittest import errno import Cookie try: import crypt except ImportError: crypt = None # Don't use cStringIO because we're going to inherit from StringIO import StringIO try: from Mailman import __init__ except ImportError: import paths from Mailman import mm_cfg from Mailman import Utils from Mailman import Errors from Mailman.Utils import md5_new, sha_new from TestBase import TestBase def password(plaintext): return sha_new(plaintext).hexdigest() class TestSecurityManager(TestBase): def test_init_vars(self): eq = self.assertEqual eq(self._mlist.mod_password, None) eq(self._mlist.passwords, {}) def test_auth_context_info_authuser(self): mlist = self._mlist self.assertRaises(TypeError, mlist.AuthContextInfo, mm_cfg.AuthUser) # Add a member mlist.addNewMember('aperson@dom.ain', password='xxXXxx') self.assertEqual( mlist.AuthContextInfo(mm_cfg.AuthUser, 'aperson@dom.ain'), ('_xtest+user+aperson--at--dom.ain', 'xxXXxx')) def test_auth_context_moderator(self): mlist = self._mlist mlist.mod_password = 'yyYYyy' self.assertEqual( mlist.AuthContextInfo(mm_cfg.AuthListModerator), ('_xtest+moderator', 'yyYYyy')) def test_auth_context_admin(self): mlist = self._mlist mlist.password = 'zzZZzz' self.assertEqual( mlist.AuthContextInfo(mm_cfg.AuthListAdmin), ('_xtest+admin', 'zzZZzz')) def test_auth_context_site(self): mlist = self._mlist mlist.password = 'aaAAaa' self.assertEqual( mlist.AuthContextInfo(mm_cfg.AuthSiteAdmin), ('_xtest+admin', 'aaAAaa')) def test_auth_context_huh(self): self.assertEqual( self._mlist.AuthContextInfo('foo'), (None, None)) class TestAuthenticate(TestBase): def setUp(self): TestBase.setUp(self) Utils.set_global_password('bbBBbb', siteadmin=1) Utils.set_global_password('ccCCcc', siteadmin=0) def tearDown(self): try: os.unlink(mm_cfg.SITE_PW_FILE) except OSError, e: if e.errno <> errno.ENOENT: raise try: os.unlink(mm_cfg.LISTCREATOR_PW_FILE) except OSError, e: if e.errno <> errno.ENOENT: raise TestBase.tearDown(self) def test_auth_creator(self): self.assertEqual(self._mlist.Authenticate( [mm_cfg.AuthCreator], 'ccCCcc'), mm_cfg.AuthCreator) def test_auth_creator_unauth(self): self.assertEqual(self._mlist.Authenticate( [mm_cfg.AuthCreator], 'xxxxxx'), mm_cfg.UnAuthorized) def test_auth_site_admin(self): self.assertEqual(self._mlist.Authenticate( [mm_cfg.AuthSiteAdmin], 'bbBBbb'), mm_cfg.AuthSiteAdmin) def test_auth_site_admin_unauth(self): self.assertEqual(self._mlist.Authenticate( [mm_cfg.AuthSiteAdmin], 'xxxxxx'), mm_cfg.UnAuthorized) def test_list_admin(self): self._mlist.password = password('ttTTtt') self.assertEqual(self._mlist.Authenticate( [mm_cfg.AuthListAdmin], 'ttTTtt'), mm_cfg.AuthListAdmin) def test_list_admin_unauth(self): self._mlist.password = password('ttTTtt') self.assertEqual(self._mlist.Authenticate( [mm_cfg.AuthListAdmin], 'xxxxxx'), mm_cfg.UnAuthorized) def test_list_admin_upgrade(self): eq = self.assertEqual mlist = self._mlist mlist.password = md5_new('ssSSss').digest() eq(mlist.Authenticate( [mm_cfg.AuthListAdmin], 'ssSSss'), mm_cfg.AuthListAdmin) eq(mlist.password, password('ssSSss')) # Test crypt upgrades if crypt is supported if crypt: mlist.password = crypt.crypt('rrRRrr', 'zc') eq(self._mlist.Authenticate( [mm_cfg.AuthListAdmin], 'rrRRrr'), mm_cfg.AuthListAdmin) eq(mlist.password, password('rrRRrr')) def test_list_admin_oldstyle_unauth(self): eq = self.assertEqual mlist = self._mlist mlist.password = md5_new('ssSSss').digest() eq(mlist.Authenticate( [mm_cfg.AuthListAdmin], 'xxxxxx'), mm_cfg.UnAuthorized) eq(mlist.password, md5_new('ssSSss').digest()) # Test crypt upgrades if crypt is supported if crypt: mlist.password = crypted = crypt.crypt('rrRRrr', 'zc') eq(self._mlist.Authenticate( [mm_cfg.AuthListAdmin], 'xxxxxx'), mm_cfg.UnAuthorized) eq(mlist.password, crypted) def test_list_moderator(self): self._mlist.mod_password = password('mmMMmm') self.assertEqual(self._mlist.Authenticate( [mm_cfg.AuthListModerator], 'mmMMmm'), mm_cfg.AuthListModerator) def test_user(self): mlist = self._mlist mlist.addNewMember('aperson@dom.ain', password='nosrepa') self.assertEqual(mlist.Authenticate( [mm_cfg.AuthUser], 'nosrepa', 'aperson@dom.ain'), mm_cfg.AuthUser) def test_wrong_user(self): mlist = self._mlist mlist.addNewMember('aperson@dom.ain', password='nosrepa') self.assertEqual(mlist.Authenticate( [mm_cfg.AuthUser], 'nosrepa', 'bperson@dom.ain'), mm_cfg.UnAuthorized) def test_no_user(self): mlist = self._mlist mlist.addNewMember('aperson@dom.ain', password='nosrepa') self.assertEqual(mlist.Authenticate( [mm_cfg.AuthUser], 'nosrepa'), mm_cfg.UnAuthorized) def test_user_unauth(self): mlist = self._mlist mlist.addNewMember('aperson@dom.ain', password='nosrepa') self.assertEqual(mlist.Authenticate( [mm_cfg.AuthUser], 'xxxxxx', 'aperson@dom.ain'), mm_cfg.UnAuthorized) def test_value_error(self): self.assertRaises(ValueError, self._mlist.Authenticate, ['spooge'], 'xxxxxx', 'zperson@dom.ain') class StripperIO(StringIO): HEAD = 'Set-Cookie: ' def write(self, s): if s.startswith(self.HEAD): s = s[len(self.HEAD):] StringIO.write(self, s) class TestWebAuthenticate(TestBase): def setUp(self): TestBase.setUp(self) Utils.set_global_password('bbBBbb', siteadmin=1) Utils.set_global_password('ccCCcc', siteadmin=0) mlist = self._mlist mlist.mod_password = password('abcdefg') mlist.addNewMember('aperson@dom.ain', password='qqQQqq') # Set up the cookie data sfp = StripperIO() print >> sfp, mlist.MakeCookie(mm_cfg.AuthSiteAdmin) # AuthCreator isn't handled in AuthContextInfo() print >> sfp, mlist.MakeCookie(mm_cfg.AuthListAdmin) print >> sfp, mlist.MakeCookie(mm_cfg.AuthListModerator) print >> sfp, mlist.MakeCookie(mm_cfg.AuthUser, 'aperson@dom.ain') # Strip off the "Set-Cookie: " prefix cookie = sfp.getvalue() os.environ['HTTP_COOKIE'] = cookie def tearDown(self): try: os.unlink(mm_cfg.SITE_PW_FILE) except OSError, e: if e.errno <> errno.ENOENT: raise try: os.unlink(mm_cfg.LISTCREATOR_PW_FILE) except OSError, e: if e.errno <> errno.ENOENT: raise del os.environ['HTTP_COOKIE'] TestBase.tearDown(self) def test_auth_site_admin(self): self.assertEqual(self._mlist.WebAuthenticate( [mm_cfg.AuthSiteAdmin], 'xxxxxx'), 1) def test_list_admin(self): self.assertEqual(self._mlist.WebAuthenticate( [mm_cfg.AuthListAdmin], 'xxxxxx'), 1) def test_list_moderator(self): self.assertEqual(self._mlist.WebAuthenticate( [mm_cfg.AuthListModerator], 'xxxxxx'), 1) def test_user(self): self.assertEqual(self._mlist.WebAuthenticate( [mm_cfg.AuthUser], 'xxxxxx'), 1) def test_not_a_user(self): self._mlist.removeMember('aperson@dom.ain') self.assertEqual(self._mlist.WebAuthenticate( [mm_cfg.AuthUser], 'xxxxxx', 'aperson@dom.ain'), 0) # TBD: Tests for MakeCookie(), ZapCookie(), CheckCookie() -- although the # latter is implicitly tested by testing WebAuthenticate() above. def suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TestSecurityManager)) suite.addTest(unittest.makeSuite(TestAuthenticate)) suite.addTest(unittest.makeSuite(TestWebAuthenticate)) return suite if __name__ == '__main__': unittest.main(defaultTest='suite')