Skip to content

Commit

Permalink
Refactor the mac group tests
Browse files Browse the repository at this point in the history
 - Simplify setup and teardown logic with user/group.present/absent
 - Added a function for asserting salt-call with no return code
 - Skip tests if required modules and states aren't available
  • Loading branch information
Akm0d committed Jan 14, 2020
1 parent 7f9fd64 commit 680790a
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 69 deletions.
130 changes: 61 additions & 69 deletions tests/integration/shell/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,18 @@
except ImportError:
pwd, grp = None, None
import random
import string

# Import Salt Testing libs
from tests.support.case import ShellCase
from tests.support.unit import skipIf
from tests.support.helpers import destructiveTest, skip_if_not_root
from tests.support.case import ShellCase, ModuleCase
from tests.support.mixins import SaltReturnAssertsMixin
from tests.support.helpers import (
destructiveTest,
requires_salt_modules,
requires_salt_states,
skip_if_not_root,
)

# Import Salt libs
import salt.utils.platform
Expand All @@ -33,68 +40,32 @@ def gen_password():
'''
generate a password and hash it
'''
alphabet = ('abcdefghijklmnopqrstuvwxyz'
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ')
password = ''
# generate password
for _ in range(20):
next_index = random.randrange(len(alphabet))
password += alphabet[next_index]

# hash the password
password = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(20))
hashed_pwd = gen_hash('salt', password, 'sha512')

return (password, hashed_pwd)
return password, hashed_pwd


@requires_salt_states('user.absent', 'user.present')
@requires_salt_modules('shadow.set_password')
@skip_if_not_root
@skipIf(pwd is None, 'Skip if no pwd module exists')
@skipIf(pwd is None or grp is None, 'No crypt module available')
@destructiveTest
class AuthTest(ShellCase):
class UserAuthTest(ModuleCase, SaltReturnAssertsMixin, ShellCase):
'''
Test auth mechanisms
Test user auth mechanisms
'''

_call_binary_ = 'salt'

userA = 'saltdev'
userB = 'saltadm'
group = 'saltops'
user = 'saltdev'

def setUp(self):
for user in (self.userA, self.userB):
try:
if salt.utils.platform.is_darwin() and user not in str(self.run_call('user.list_users')):
# workaround for https://github.com/saltstack/salt-jenkins/issues/504
raise KeyError
pwd.getpwnam(user)
except KeyError:
self.run_call('user.add {0} createhome=False'.format(user))

# only put userB into the group for the group auth test
try:
if salt.utils.platform.is_darwin() and self.group not in str(self.run_call('group.info {0}'.format(self.group))):
# workaround for https://github.com/saltstack/salt-jenkins/issues/504
raise KeyError
grp.getgrnam(self.group)
except KeyError:
self.run_call('group.add {0}'.format(self.group))
self.run_call('user.chgroups {0} {1} True'.format(self.userB, self.group))
ret = self.run_state('user.present', name=self.user, createhome=False)
self.assertSaltTrueReturn(ret)

def tearDown(self):
for user in (self.userA, self.userB):
try:
pwd.getpwnam(user)
except KeyError:
pass
else:
self.run_call('user.delete {0}'.format(user))
try:
grp.getgrnam(self.group)
except KeyError:
pass
else:
self.run_call('group.delete {0}'.format(self.group))
ret = self.run_state('user.absent', name=self.user)
self.assertSaltTrueReturn(ret)

def test_pam_auth_valid_user(self):
'''
Expand All @@ -104,19 +75,16 @@ def test_pam_auth_valid_user(self):

# set user password
set_pw_cmd = "shadow.set_password {0} '{1}'".format(
self.userA,
password if salt.utils.platform.is_darwin() else hashed_pwd
self.user,
password if salt.utils.platform.is_darwin() else hashed_pwd
)
self.run_call(set_pw_cmd)
self.assertRunCall(set_pw_cmd)

# test user auth against pam
cmd = ('-a pam "*" test.ping '
'--username {0} --password {1}'.format(self.userA, password))
cmd = ('-a pam "*" test.ping --username {0} --password {1}'.format(self.user, password))
resp = self.run_salt(cmd)
log.debug('resp = %s', resp)
self.assertTrue(
'minion:' in resp
)
self.assertIn('minion', [r.strip(': ') for r in resp])

def test_pam_auth_invalid_user(self):
'''
Expand All @@ -125,9 +93,36 @@ def test_pam_auth_invalid_user(self):
cmd = ('-a pam "*" test.ping '
'--username nouser --password {0}'.format('abcd1234'))
resp = self.run_salt(cmd)
self.assertTrue(
'Authentication error occurred.' in ''.join(resp)
)
self.assertIn('Authentication error occurred', ''.join(resp))


@requires_salt_states('group.absent', 'group.present', 'user.absent', 'user.present')
@requires_salt_modules('shadow.set_password', 'user.chgroups')
@skip_if_not_root
@skipIf(pwd is None or grp is None, 'No crypt module available')
@destructiveTest
class GroupAuthTest(ModuleCase, SaltReturnAssertsMixin, ShellCase):
'''
Test group auth mechanisms
'''

_call_binary_ = 'salt'

user = 'saltadm'
group = 'saltops'

def setUp(self):
ret = self.run_state('group.present', name=self.group)
self.assertSaltTrueReturn(ret)
ret = self.run_state('user.present', name=self.user, createhome=False, groups=[self.group])
self.assertSaltTrueReturn(ret)
self.assertRunCall('user.chgroups {0} {1} True'.format(self.user, self.group), local=True)

def tearDown(self):
ret0 = self.run_state('user.absent', name=self.user)
ret1 = self.run_state('group.absent', name=self.group)
self.assertSaltTrueReturn(ret0)
self.assertSaltTrueReturn(ret1)

def test_pam_auth_valid_group(self):
'''
Expand All @@ -137,16 +132,13 @@ def test_pam_auth_valid_group(self):

# set user password
set_pw_cmd = "shadow.set_password {0} '{1}'".format(
self.userB,
password if salt.utils.platform.is_darwin() else hashed_pwd
self.user,
password if salt.utils.platform.is_darwin() else hashed_pwd
)
self.run_call(set_pw_cmd)
self.assertRunCall(set_pw_cmd)

# test group auth against pam: saltadm is not configured in
# external_auth, but saltops is and saldadm is a member of saltops
cmd = ('-a pam "*" test.ping '
'--username {0} --password {1}'.format(self.userB, password))
cmd = ('-a pam "*" test.ping --username {0} --password {1}'.format(self.user, password))
resp = self.run_salt(cmd)
self.assertTrue(
'minion:' in resp
)
self.assertIn('minion', [r.strip(': ') for r in resp])
10 changes: 10 additions & 0 deletions tests/support/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@ def run_call(self, arg_str, with_retcode=False, catch_stderr=False, local=False,
catch_stderr=catch_stderr,
timeout=timeout)

def assertRunCall(self, arg_str, **kwargs):
'''
Assert no error code was returned with run_call, give stderr as error message
'''
stdout, stderr, retcode = self.run_call(arg_str, catch_stderr=True, with_retcode=True, **kwargs)
if stderr:
log.warning(stderr)
self.assertFalse(retcode, stderr)
return stdout

def run_cloud(self, arg_str, catch_stderr=False, timeout=None):
'''
Execute salt-cloud
Expand Down

0 comments on commit 680790a

Please sign in to comment.