# ⁻*- coding: utf-8 -*- # 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 version 3 for # more details. # # You should have received a copy of the GNU General Public License version 3 # along with this program; if not, write to the Free Software Foundation, Inc., 51 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # (c) 2016 Valentin Samir """Tests module for utils""" from django.test import TestCase import six from cas_server import utils class CheckPasswordCase(TestCase): """Tests for the utils function `utils.check_password`""" def setUp(self): """Generate random bytes string that will be used ass passwords""" self.password1 = utils.gen_saml_id() self.password2 = utils.gen_saml_id() if not isinstance(self.password1, bytes): # pragma: no cover executed only in python3 self.password1 = self.password1.encode("utf8") self.password2 = self.password2.encode("utf8") def test_setup(self): """check that generated password are bytes""" self.assertIsInstance(self.password1, bytes) self.assertIsInstance(self.password2, bytes) def test_plain(self): """test the plain auth method""" self.assertTrue(utils.check_password("plain", self.password1, self.password1, "utf8")) self.assertFalse(utils.check_password("plain", self.password1, self.password2, "utf8")) def test_plain_unicode(self): """test the plain auth method with unicode input""" self.assertTrue( utils.check_password( "plain", self.password1.decode("utf8"), self.password1.decode("utf8"), "utf8" ) ) self.assertFalse( utils.check_password( "plain", self.password1.decode("utf8"), self.password2.decode("utf8"), "utf8" ) ) def test_crypt(self): """test the crypt auth method""" salts = ["$6$UVVAQvrMyXMF3FF3", "aa"] hashed_password1 = [] for salt in salts: if six.PY3: hashed_password1.append( utils.crypt.crypt( self.password1.decode("utf8"), salt ).encode("utf8") ) else: hashed_password1.append(utils.crypt.crypt(self.password1, salt)) for hp1 in hashed_password1: self.assertTrue(utils.check_password("crypt", self.password1, hp1, "utf8")) self.assertFalse(utils.check_password("crypt", self.password2, hp1, "utf8")) with self.assertRaises(ValueError): utils.check_password("crypt", self.password1, b"$truc$s$dsdsd", "utf8") def test_ldap_password_valid(self): """test the ldap auth method with all the schemes""" salt = b"UVVAQvrMyXMF3FF3" schemes_salt = [b"{SMD5}", b"{SSHA}", b"{SSHA256}", b"{SSHA384}", b"{SSHA512}"] schemes_nosalt = [b"{MD5}", b"{SHA}", b"{SHA256}", b"{SHA384}", b"{SHA512}"] hashed_password1 = [] for scheme in schemes_salt: hashed_password1.append( utils.LdapHashUserPassword.hash(scheme, self.password1, salt, charset="utf8") ) for scheme in schemes_nosalt: hashed_password1.append( utils.LdapHashUserPassword.hash(scheme, self.password1, charset="utf8") ) hashed_password1.append( utils.LdapHashUserPassword.hash( b"{CRYPT}", self.password1, b"$6$UVVAQvrMyXMF3FF3", charset="utf8" ) ) for hp1 in hashed_password1: self.assertIsInstance(hp1, bytes) self.assertTrue(utils.check_password("ldap", self.password1, hp1, "utf8")) self.assertFalse(utils.check_password("ldap", self.password2, hp1, "utf8")) def test_ldap_password_fail(self): """test the ldap auth method with malformed hash or bad schemes""" salt = b"UVVAQvrMyXMF3FF3" schemes_salt = [b"{SMD5}", b"{SSHA}", b"{SSHA256}", b"{SSHA384}", b"{SSHA512}"] schemes_nosalt = [b"{MD5}", b"{SHA}", b"{SHA256}", b"{SHA384}", b"{SHA512}"] # first try to hash with bad parameters with self.assertRaises(utils.LdapHashUserPassword.BadScheme): utils.LdapHashUserPassword.hash(b"TOTO", self.password1) for scheme in schemes_nosalt: with self.assertRaises(utils.LdapHashUserPassword.BadScheme): utils.LdapHashUserPassword.hash(scheme, self.password1, salt) for scheme in schemes_salt: with self.assertRaises(utils.LdapHashUserPassword.BadScheme): utils.LdapHashUserPassword.hash(scheme, self.password1) with self.assertRaises(utils.LdapHashUserPassword.BadSalt): utils.LdapHashUserPassword.hash(b'{CRYPT}', self.password1, b"$truc$toto") # then try to check hash with bad hashes with self.assertRaises(utils.LdapHashUserPassword.BadHash): utils.check_password("ldap", self.password1, b"TOTOssdsdsd", "utf8") for scheme in schemes_salt: with self.assertRaises(utils.LdapHashUserPassword.BadHash): utils.check_password("ldap", self.password1, scheme + b"dG90b3E8ZHNkcw==", "utf8") def test_hex(self): """test all the hex_HASH method: the hashed password is a simple hash of the password""" hashes = ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"] hashed_password1 = [] for hash in hashes: hashed_password1.append( ("hex_%s" % hash, getattr(utils.hashlib, hash)(self.password1).hexdigest()) ) for (method, hp1) in hashed_password1: self.assertTrue(utils.check_password(method, self.password1, hp1, "utf8")) self.assertFalse(utils.check_password(method, self.password2, hp1, "utf8")) def test_bad_method(self): """try to check password with a bad method, should raise a ValueError""" with self.assertRaises(ValueError): utils.check_password("test", self.password1, b"$truc$s$dsdsd", "utf8") class UtilsTestCase(TestCase): """tests for some little utils functions""" def test_import_attr(self): """ test the import_attr function. Feeded with a dotted path string, it should import the dotted module and return that last componend of the dotted path (function, class or variable) """ with self.assertRaises(ImportError): utils.import_attr('toto.titi.tutu') with self.assertRaises(AttributeError): utils.import_attr('cas_server.utils.toto') with self.assertRaises(ValueError): utils.import_attr('toto') self.assertEqual( utils.import_attr('cas_server.default_app_config'), 'cas_server.apps.CasAppConfig' ) self.assertEqual(utils.import_attr(utils), utils) def test_update_url(self): """ test the update_url function. Given an url with possible GET parameter and a dict the function build a url with GET parameters updated by the dictionnary """ url1 = utils.update_url(u"https://www.example.com?toto=1", {u"tata": u"2"}) url2 = utils.update_url(b"https://www.example.com?toto=1", {b"tata": b"2"}) self.assertEqual(url1, u"https://www.example.com?tata=2&toto=1") self.assertEqual(url2, u"https://www.example.com?tata=2&toto=1") url3 = utils.update_url(u"https://www.example.com?toto=1", {u"toto": u"2"}) self.assertEqual(url3, u"https://www.example.com?toto=2") def test_crypt_salt_is_valid(self): """test the function crypt_salt_is_valid who test if a crypt salt is valid""" self.assertFalse(utils.crypt_salt_is_valid("")) # len 0 self.assertFalse(utils.crypt_salt_is_valid("a")) # len 1 self.assertFalse(utils.crypt_salt_is_valid("$$")) # start with $ followed by $ self.assertFalse(utils.crypt_salt_is_valid("$toto")) # start with $ but no secondary $ self.assertFalse(utils.crypt_salt_is_valid("$toto$toto")) # algorithm toto not known