123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- # -*- coding: utf-8 -*-
- from __future__ import absolute_import, print_function, unicode_literals
- import re
- import salt.utils.platform
- import salt.utils.pycrypto
- from salt.exceptions import SaltInvocationError
- from tests.support.mock import patch
- from tests.support.unit import TestCase, skipIf
- class PycryptoTestCase(TestCase):
- """
- TestCase for salt.utils.pycrypto module
- """
- passwd = "test_password"
- expecteds = {
- "sha512": {
- "hashed": "$6$rounds=65601$goodsalt$lZFhiN5M8RTLd9WKDin50H4lF4F8HGMIdwvKs.nTG7f8F0Y4P447Zb9/E8SkUWjY.K10QT3NuHZNDgc/P/NjT1",
- "salt": "rounds=65601$goodsalt",
- "badsalt": "badsalt",
- },
- "sha256": {
- "hashed": "$5$rounds=53501$goodsalt$W.uoco0wMfGLDOlsbW52E6raFS1Nhj0McfUTj2vORt7",
- "salt": "rounds=53501$goodsalt",
- "badsalt": "badsalt",
- },
- "blowfish": {
- "hashed": "$2b$10$goodsaltgoodsaltgoodsObFfGrJwfV.13QddrZIh2w1ccESmvj8K",
- "salt": "10$goodsaltgoodsaltgoodsa",
- "badsalt": "badsaltbadsaltbadsaltb",
- },
- "md5": {
- "hashed": "$1$goodsalt$4XQMx4a4e1MpBB8xzz.TQ0",
- "salt": "goodsalt",
- "badsalt": "badsalt",
- },
- "crypt": {"hashed": "goVHulDpuGA7w", "salt": "go", "badsalt": "ba"},
- }
- invalid_salt = "thissaltistoolong" * 10
- @skipIf(not salt.utils.pycrypto.HAS_CRYPT, "crypt not available")
- def test_gen_hash_crypt(self):
- """
- Test gen_hash with crypt library
- """
- methods = salt.utils.pycrypto.methods
- for algorithm in methods:
- expected = self.expecteds[algorithm]
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=expected["salt"], password=self.passwd, algorithm=algorithm,
- )
- self.assertEqual(ret, expected["hashed"])
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=expected["badsalt"],
- password=self.passwd,
- algorithm=algorithm,
- )
- self.assertNotEqual(ret, expected["hashed"])
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=None, password=self.passwd, algorithm=algorithm
- )
- self.assertNotEqual(ret, expected["hashed"])
- # Assert it works without arguments passed
- self.assertIsNotNone(salt.utils.pycrypto.gen_hash())
- # Assert it works without algorithm passed
- default_algorithm = salt.utils.pycrypto.crypt.methods[0].name.lower()
- expected = self.expecteds[default_algorithm]
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=expected["salt"], password=self.passwd,
- )
- self.assertEqual(ret, expected["hashed"])
- @skipIf(not salt.utils.pycrypto.HAS_PASSLIB, "passlib not available")
- @patch("salt.utils.pycrypto.methods", {})
- @patch("salt.utils.pycrypto.HAS_CRYPT", False)
- def test_gen_hash_passlib(self):
- """
- Test gen_hash with passlib
- """
- methods = salt.utils.pycrypto.known_methods
- for algorithm in methods:
- expected = self.expecteds[algorithm]
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=expected["salt"], password=self.passwd, algorithm=algorithm,
- )
- self.assertEqual(ret, expected["hashed"])
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=expected["badsalt"],
- password=self.passwd,
- algorithm=algorithm,
- )
- self.assertNotEqual(ret, expected["hashed"])
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=None, password=self.passwd, algorithm=algorithm
- )
- self.assertNotEqual(ret, expected["hashed"])
- # Assert it works without arguments passed
- self.assertIsNotNone(salt.utils.pycrypto.gen_hash())
- # Assert it works without algorithm passed
- default_algorithm = salt.utils.pycrypto.known_methods[0]
- expected = self.expecteds[default_algorithm]
- if default_algorithm in self.expecteds:
- ret = salt.utils.pycrypto.gen_hash(
- crypt_salt=expected["salt"], password=self.passwd
- )
- self.assertEqual(ret, expected["hashed"])
- @patch("salt.utils.pycrypto.HAS_CRYPT", False)
- @patch("salt.utils.pycrypto.HAS_PASSLIB", False)
- def test_gen_hash_no_lib(self):
- """
- test gen_hash with no crypt library available
- """
- with self.assertRaises(SaltInvocationError):
- salt.utils.pycrypto.gen_hash()
- @patch("salt.utils.pycrypto.HAS_CRYPT", True)
- @patch("salt.utils.pycrypto.methods", {"crypt": None})
- @patch("salt.utils.pycrypto.HAS_PASSLIB", True)
- def test_gen_hash_selection(self):
- """
- verify the hash backend selection works correctly
- """
- with patch("salt.utils.pycrypto._gen_hash_crypt", autospec=True) as gh_crypt:
- with patch(
- "salt.utils.pycrypto._gen_hash_passlib", autospec=True
- ) as gh_passlib:
- with self.assertRaises(SaltInvocationError):
- salt.utils.pycrypto.gen_hash(algorithm="doesntexist")
- salt.utils.pycrypto.gen_hash(algorithm="crypt")
- gh_crypt.assert_called_once()
- gh_passlib.assert_not_called()
- gh_crypt.reset_mock()
- salt.utils.pycrypto.gen_hash(algorithm="sha512")
- gh_crypt.assert_not_called()
- gh_passlib.assert_called_once()
- def test_gen_hash_crypt_warning(self):
- """
- Verify that a bad crypt salt triggers a warning
- """
- with patch("salt.utils.pycrypto.log", autospec=True) as log:
- try:
- salt.utils.pycrypto.gen_hash(
- crypt_salt="toolong", password=self.passwd, algorithm="crypt"
- )
- except Exception: # pylint: disable=broad-except
- pass
- log.warning.assert_called_with("Hash salt is too long for 'crypt' hash.")
- def test_secure_password(self):
- """
- test secure_password
- """
- ret = salt.utils.pycrypto.secure_password()
- check = re.compile(r"[!@#$%^&*()_=+]")
- self.assertIsNone(check.search(ret))
- self.assertTrue(ret)
|