diff --git a/cas_server/tests/test_utils.py b/cas_server/tests/test_utils.py index d298ba7..76fa2cc 100644 --- a/cas_server/tests/test_utils.py +++ b/cas_server/tests/test_utils.py @@ -181,3 +181,11 @@ class UtilsTestCase(TestCase): 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 diff --git a/cas_server/utils.py b/cas_server/utils.py index 060e9ab..ee7b5e5 100644 --- a/cas_server/utils.py +++ b/cas_server/utils.py @@ -89,7 +89,7 @@ def update_url(url, params): query = list(query.items()) query.sort() url_query = urlencode(query) - if not isinstance(url_query, bytes): + if not isinstance(url_query, bytes): # pragma: no cover in python3 urlencode return an unicode url_query = url_query.encode("utf-8") url_parts[4] = url_query return urlunparse(url_parts).decode('utf-8') @@ -152,6 +152,27 @@ def gen_saml_id(): return _gen_ticket('_') +def crypt_salt_is_valid(salt): + """Return True is salt is valid has a crypt salt, False otherwise""" + if len(salt) < 2: + return False + else: + if salt[0] == '$': + if salt[1] == '$': + return False + else: + if '$' not in salt[1:]: + return False + else: + hashed = crypt.crypt("", salt) + if not hashed or '$' not in hashed[1:]: + return False + else: + return True + else: + return True + + class LdapHashUserPassword(object): """Please see https://tools.ietf.org/id/draft-stroeder-hashed-userpassword-values-01.html""" @@ -252,9 +273,9 @@ class LdapHashUserPassword(object): if six.PY3: password = password.decode(charset) salt = salt.decode(charset) - hashed_password = crypt.crypt(password, salt) - if hashed_password is None: + if not crypt_salt_is_valid(salt): raise cls.BadSalt("System crypt implementation do not support the salt %r" % salt) + hashed_password = crypt.crypt(password, salt) if six.PY3: hashed_password = hashed_password.encode(charset) return scheme + hashed_password @@ -306,9 +327,9 @@ def check_password(method, password, hashed_password, charset): password = password.decode(charset) salt = salt.decode(charset) hashed_password = hashed_password.decode(charset) - crypted_password = crypt.crypt(password, salt) - if crypted_password is None: + if not crypt_salt_is_valid(salt): raise ValueError("System crypt implementation do not support the salt %r" % salt) + crypted_password = crypt.crypt(password, salt) return crypted_password == hashed_password elif method == "ldap": scheme = LdapHashUserPassword.get_scheme(hashed_password)