test_auth.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. # -*- coding: utf-8 -*-
  2. """
  3. tests.integration.shell.auth
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. """
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import logging
  8. import random
  9. import string
  10. import pytest
  11. import salt.utils.platform
  12. from salt.ext.six.moves import range
  13. from salt.utils.pycrypto import gen_hash
  14. from tests.support.case import ModuleCase, ShellCase
  15. from tests.support.helpers import (
  16. destructiveTest,
  17. requires_salt_modules,
  18. requires_salt_states,
  19. skip_if_not_root,
  20. slowTest,
  21. )
  22. from tests.support.mixins import SaltReturnAssertsMixin
  23. from tests.support.unit import skipIf
  24. try:
  25. import pwd
  26. import grp
  27. except ImportError:
  28. pwd, grp = None, None
  29. log = logging.getLogger(__name__)
  30. def gen_password():
  31. """
  32. generate a password and hash it
  33. """
  34. password = "".join(
  35. random.choice(string.ascii_letters + string.digits) for _ in range(20)
  36. )
  37. hashed_pwd = (
  38. password
  39. if salt.utils.platform.is_darwin()
  40. else gen_hash("salt", password, "sha512")
  41. )
  42. return password, hashed_pwd
  43. @requires_salt_states("user.absent", "user.present")
  44. @requires_salt_modules("shadow.set_password")
  45. @skip_if_not_root
  46. @skipIf(pwd is None or grp is None, "No pwd or grp module available")
  47. @destructiveTest
  48. @pytest.mark.windows_whitelisted
  49. class UserAuthTest(ModuleCase, SaltReturnAssertsMixin, ShellCase):
  50. """
  51. Test user auth mechanisms
  52. """
  53. _call_binary_ = "salt"
  54. user = "saltdev"
  55. def setUp(self):
  56. ret = self.run_state("user.present", name=self.user, createhome=False)
  57. self.assertSaltTrueReturn(ret)
  58. def tearDown(self):
  59. ret = self.run_state("user.absent", name=self.user)
  60. self.assertSaltTrueReturn(ret)
  61. @slowTest
  62. def test_pam_auth_valid_user(self):
  63. """
  64. test that pam auth mechanism works with a valid user
  65. """
  66. password, hashed_pwd = gen_password()
  67. # set user password
  68. set_pw_cmd = "shadow.set_password {0} '{1}'".format(self.user, hashed_pwd)
  69. stdout, stderr, retcode = self.run_call(
  70. set_pw_cmd, catch_stderr=True, with_retcode=True
  71. )
  72. if stderr:
  73. log.warning(stderr)
  74. self.assertFalse(retcode, stderr)
  75. # test user auth against pam
  76. cmd = '-a pam "*" test.ping --username {0} --password {1}'.format(
  77. self.user, password
  78. )
  79. resp = self.run_salt(cmd)
  80. log.debug("resp = %s", resp)
  81. self.assertIn("minion", [r.strip(": ") for r in resp])
  82. @slowTest
  83. def test_pam_auth_invalid_user(self):
  84. """
  85. test pam auth mechanism errors for an invalid user
  86. """
  87. cmd = '-a pam "*" test.ping ' "--username nouser --password {0}".format(
  88. "abcd1234"
  89. )
  90. resp = self.run_salt(cmd)
  91. self.assertIn("Authentication error occurred", "".join(resp))
  92. @requires_salt_states("group.absent", "group.present", "user.absent", "user.present")
  93. @requires_salt_modules("shadow.set_password", "user.chgroups")
  94. @skip_if_not_root
  95. @skipIf(pwd is None or grp is None, "No crypt module available")
  96. @destructiveTest
  97. class GroupAuthTest(ModuleCase, SaltReturnAssertsMixin, ShellCase):
  98. """
  99. Test group auth mechanisms
  100. """
  101. _call_binary_ = "salt"
  102. user = "saltadm"
  103. group = "saltops"
  104. def setUp(self):
  105. ret = self.run_state("group.present", name=self.group)
  106. self.assertSaltTrueReturn(ret)
  107. ret = self.run_state(
  108. "user.present", name=self.user, createhome=False, groups=[self.group]
  109. )
  110. self.assertSaltTrueReturn(ret)
  111. stdout, stderr, retcode = self.run_call(
  112. "user.chgroups {0} {1} True".format(self.user, self.group),
  113. local=True,
  114. with_retcode=True,
  115. catch_stderr=True,
  116. )
  117. if stderr:
  118. log.warning(stderr)
  119. self.assertFalse(retcode, stderr)
  120. def tearDown(self):
  121. ret0 = self.run_state("user.absent", name=self.user)
  122. ret1 = self.run_state("group.absent", name=self.group)
  123. self.assertSaltTrueReturn(ret0)
  124. self.assertSaltTrueReturn(ret1)
  125. @slowTest
  126. def test_pam_auth_valid_group(self):
  127. """
  128. test that pam auth mechanism works for a valid group
  129. """
  130. password, hashed_pwd = gen_password()
  131. # set user password
  132. set_pw_cmd = "shadow.set_password {0} '{1}'".format(self.user, hashed_pwd)
  133. stdout, stderr, retcode = self.run_call(
  134. set_pw_cmd, catch_stderr=True, with_retcode=True
  135. )
  136. if stderr:
  137. log.warning(stderr)
  138. self.assertFalse(retcode, stderr)
  139. # test group auth against pam: saltadm is not configured in
  140. # external_auth, but saltops is and saldadm is a member of saltops
  141. cmd = '-a pam "*" test.ping --username {0} --password {1}'.format(
  142. self.user, password
  143. )
  144. resp = self.run_salt(cmd)
  145. self.assertIn("minion", [r.strip(": ") for r in resp])