2013-11-27 11:19:24 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2012-05-20 17:06:04 +00:00
|
|
|
'''
|
|
|
|
Test the ssh module
|
|
|
|
'''
|
|
|
|
# Import python libs
|
2014-11-21 19:05:13 +00:00
|
|
|
from __future__ import absolute_import
|
2012-05-20 17:06:04 +00:00
|
|
|
import os
|
|
|
|
import shutil
|
|
|
|
|
2013-06-27 11:42:38 +00:00
|
|
|
# Import Salt Testing libs
|
2017-04-03 16:04:09 +00:00
|
|
|
from tests.support.case import ModuleCase
|
|
|
|
from tests.support.paths import FILES, TMP
|
2017-02-27 15:59:04 +00:00
|
|
|
from tests.support.helpers import skip_if_binaries_missing
|
2013-06-27 11:42:38 +00:00
|
|
|
|
|
|
|
# Import salt libs
|
2017-07-18 16:31:01 +00:00
|
|
|
import salt.utils.files
|
2017-04-18 11:26:06 +00:00
|
|
|
|
|
|
|
# Import 3rd-party libs
|
|
|
|
from tornado.httpclient import HTTPClient
|
2012-05-20 17:06:04 +00:00
|
|
|
|
2017-04-03 16:04:09 +00:00
|
|
|
SUBSALT_DIR = os.path.join(TMP, 'subsalt')
|
2013-09-05 22:32:48 +00:00
|
|
|
AUTHORIZED_KEYS = os.path.join(SUBSALT_DIR, 'authorized_keys')
|
|
|
|
KNOWN_HOSTS = os.path.join(SUBSALT_DIR, 'known_hosts')
|
2017-05-11 15:33:45 +00:00
|
|
|
GITHUB_FINGERPRINT = '9d:38:5b:83:a9:17:52:92:56:1a:5e:c4:d4:81:8e:0a:ca:51:a2:64:f1:74:20:11:2e:f8:8a:c3:a1:39:49:8f'
|
2012-05-20 17:06:04 +00:00
|
|
|
|
|
|
|
|
2016-10-21 10:47:05 +00:00
|
|
|
def check_status():
|
|
|
|
'''
|
|
|
|
Check the status of Github for remote operations
|
|
|
|
'''
|
2017-04-18 11:26:06 +00:00
|
|
|
try:
|
|
|
|
return HTTPClient().fetch('http://github.com').code == 200
|
|
|
|
except Exception: # pylint: disable=broad-except
|
|
|
|
return False
|
2016-10-21 10:47:05 +00:00
|
|
|
|
|
|
|
|
2014-02-08 07:45:25 +00:00
|
|
|
@skip_if_binaries_missing(['ssh', 'ssh-keygen'], check_all=True)
|
2017-04-03 16:04:09 +00:00
|
|
|
class SSHModuleTest(ModuleCase):
|
2012-05-20 17:06:04 +00:00
|
|
|
'''
|
|
|
|
Test the ssh module
|
|
|
|
'''
|
2012-05-21 15:44:26 +00:00
|
|
|
def setUp(self):
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
|
|
|
Set up the ssh module tests
|
|
|
|
'''
|
2017-04-17 07:49:59 +00:00
|
|
|
if not check_status():
|
|
|
|
self.skipTest('External source, github.com is down')
|
2012-05-21 15:44:26 +00:00
|
|
|
super(SSHModuleTest, self).setUp()
|
2013-09-05 22:32:48 +00:00
|
|
|
if not os.path.isdir(SUBSALT_DIR):
|
|
|
|
os.makedirs(SUBSALT_DIR)
|
|
|
|
|
2017-04-03 16:04:09 +00:00
|
|
|
ssh_raw_path = os.path.join(FILES, 'ssh', 'raw')
|
2017-07-18 16:31:01 +00:00
|
|
|
with salt.utils.files.fopen(ssh_raw_path) as fd:
|
2012-05-21 15:44:26 +00:00
|
|
|
self.key = fd.read().strip()
|
|
|
|
|
2012-05-20 17:06:04 +00:00
|
|
|
def tearDown(self):
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
|
|
|
Tear down the ssh module tests
|
|
|
|
'''
|
2013-09-05 22:32:48 +00:00
|
|
|
if os.path.isdir(SUBSALT_DIR):
|
|
|
|
shutil.rmtree(SUBSALT_DIR)
|
2012-05-21 17:45:03 +00:00
|
|
|
super(SSHModuleTest, self).tearDown()
|
2017-03-06 16:45:59 +00:00
|
|
|
del self.key
|
2012-05-20 17:06:04 +00:00
|
|
|
|
|
|
|
def test_auth_keys(self):
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
|
|
|
test ssh.auth_keys
|
|
|
|
'''
|
2012-05-20 17:06:04 +00:00
|
|
|
shutil.copyfile(
|
2017-04-03 16:04:09 +00:00
|
|
|
os.path.join(FILES, 'ssh', 'authorized_keys'),
|
2012-05-20 17:06:04 +00:00
|
|
|
AUTHORIZED_KEYS)
|
|
|
|
ret = self.run_function('ssh.auth_keys', ['root', AUTHORIZED_KEYS])
|
2012-06-04 23:22:43 +00:00
|
|
|
self.assertEqual(len(list(ret.items())), 1) # exactly one key is found
|
2012-06-04 22:40:34 +00:00
|
|
|
key_data = list(ret.items())[0][1]
|
2013-08-13 23:35:58 +00:00
|
|
|
try:
|
|
|
|
self.assertEqual(key_data['comment'], 'github.com')
|
|
|
|
self.assertEqual(key_data['enc'], 'ssh-rsa')
|
|
|
|
self.assertEqual(
|
|
|
|
key_data['options'], ['command="/usr/local/lib/ssh-helper"']
|
|
|
|
)
|
|
|
|
self.assertEqual(key_data['fingerprint'], GITHUB_FINGERPRINT)
|
|
|
|
except AssertionError as exc:
|
|
|
|
raise AssertionError(
|
|
|
|
'AssertionError: {0}. Function returned: {1}'.format(
|
|
|
|
exc, ret
|
|
|
|
)
|
|
|
|
)
|
2012-05-20 17:06:04 +00:00
|
|
|
|
2013-10-15 17:48:28 +00:00
|
|
|
def test_bad_enctype(self):
|
|
|
|
'''
|
|
|
|
test to make sure that bad key encoding types don't generate an
|
|
|
|
invalid key entry in authorized_keys
|
|
|
|
'''
|
|
|
|
shutil.copyfile(
|
2017-04-03 16:04:09 +00:00
|
|
|
os.path.join(FILES, 'ssh', 'authorized_badkeys'),
|
2013-10-15 17:48:28 +00:00
|
|
|
AUTHORIZED_KEYS)
|
|
|
|
ret = self.run_function('ssh.auth_keys', ['root', AUTHORIZED_KEYS])
|
|
|
|
|
|
|
|
# The authorized_badkeys file contains a key with an invalid ssh key
|
|
|
|
# encoding (dsa-sha2-nistp256 instead of ecdsa-sha2-nistp256)
|
|
|
|
# auth_keys should skip any keys with invalid encodings. Internally
|
|
|
|
# the minion will throw a CommandExecutionError so the
|
|
|
|
# user will get an indicator of what went wrong.
|
2013-11-27 12:56:35 +00:00
|
|
|
self.assertEqual(len(list(ret.items())), 0) # Zero keys found
|
2013-10-15 17:48:28 +00:00
|
|
|
|
2017-09-13 04:54:10 +00:00
|
|
|
def test_get_known_host_entries(self):
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
2012-05-21 15:44:26 +00:00
|
|
|
Check that known host information is returned from ~/.ssh/config
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
2012-05-21 15:44:26 +00:00
|
|
|
shutil.copyfile(
|
2017-04-03 16:04:09 +00:00
|
|
|
os.path.join(FILES, 'ssh', 'known_hosts'),
|
2012-05-21 15:44:26 +00:00
|
|
|
KNOWN_HOSTS)
|
|
|
|
arg = ['root', 'github.com']
|
|
|
|
kwargs = {'config': KNOWN_HOSTS}
|
2017-09-13 04:54:10 +00:00
|
|
|
ret = self.run_function('ssh.get_known_host_entries', arg, **kwargs)[0]
|
2013-08-13 23:35:58 +00:00
|
|
|
try:
|
|
|
|
self.assertEqual(ret['enc'], 'ssh-rsa')
|
|
|
|
self.assertEqual(ret['key'], self.key)
|
|
|
|
self.assertEqual(ret['fingerprint'], GITHUB_FINGERPRINT)
|
|
|
|
except AssertionError as exc:
|
|
|
|
raise AssertionError(
|
|
|
|
'AssertionError: {0}. Function returned: {1}'.format(
|
|
|
|
exc, ret
|
|
|
|
)
|
|
|
|
)
|
2012-05-21 15:44:26 +00:00
|
|
|
|
2017-09-13 04:54:10 +00:00
|
|
|
def test_recv_known_host_entries(self):
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
2012-05-21 15:44:26 +00:00
|
|
|
Check that known host information is returned from remote host
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
2017-09-13 04:54:10 +00:00
|
|
|
ret = self.run_function('ssh.recv_known_host_entries', ['github.com'])
|
2013-08-13 23:35:58 +00:00
|
|
|
try:
|
2013-09-05 22:13:13 +00:00
|
|
|
self.assertNotEqual(ret, None)
|
2017-09-13 04:54:10 +00:00
|
|
|
self.assertEqual(ret[0]['enc'], 'ssh-rsa')
|
|
|
|
self.assertEqual(ret[0]['key'], self.key)
|
|
|
|
self.assertEqual(ret[0]['fingerprint'], GITHUB_FINGERPRINT)
|
2013-08-13 23:35:58 +00:00
|
|
|
except AssertionError as exc:
|
|
|
|
raise AssertionError(
|
|
|
|
'AssertionError: {0}. Function returned: {1}'.format(
|
|
|
|
exc, ret
|
|
|
|
)
|
|
|
|
)
|
2012-05-21 15:44:26 +00:00
|
|
|
|
|
|
|
def test_check_known_host_add(self):
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
2012-05-21 15:44:26 +00:00
|
|
|
Check known hosts by its fingerprint. File needs to be updated
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
2012-05-21 15:44:26 +00:00
|
|
|
arg = ['root', 'github.com']
|
|
|
|
kwargs = {'fingerprint': GITHUB_FINGERPRINT, 'config': KNOWN_HOSTS}
|
|
|
|
ret = self.run_function('ssh.check_known_host', arg, **kwargs)
|
|
|
|
self.assertEqual(ret, 'add')
|
|
|
|
|
|
|
|
def test_check_known_host_update(self):
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
|
|
|
ssh.check_known_host update verification
|
|
|
|
'''
|
2012-05-21 15:44:26 +00:00
|
|
|
shutil.copyfile(
|
2017-04-03 16:04:09 +00:00
|
|
|
os.path.join(FILES, 'ssh', 'known_hosts'),
|
2012-05-21 15:44:26 +00:00
|
|
|
KNOWN_HOSTS)
|
|
|
|
arg = ['root', 'github.com']
|
|
|
|
kwargs = {'config': KNOWN_HOSTS}
|
|
|
|
# wrong fingerprint
|
|
|
|
ret = self.run_function('ssh.check_known_host', arg,
|
|
|
|
**dict(kwargs, fingerprint='aa:bb:cc:dd'))
|
|
|
|
self.assertEqual(ret, 'update')
|
|
|
|
# wrong keyfile
|
|
|
|
ret = self.run_function('ssh.check_known_host', arg,
|
|
|
|
**dict(kwargs, key='YQ=='))
|
|
|
|
self.assertEqual(ret, 'update')
|
|
|
|
|
|
|
|
def test_check_known_host_exists(self):
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
|
|
|
Verify check_known_host_exists
|
|
|
|
'''
|
2012-05-21 15:44:26 +00:00
|
|
|
shutil.copyfile(
|
2017-04-03 16:04:09 +00:00
|
|
|
os.path.join(FILES, 'ssh', 'known_hosts'),
|
2012-05-21 15:44:26 +00:00
|
|
|
KNOWN_HOSTS)
|
|
|
|
arg = ['root', 'github.com']
|
|
|
|
kwargs = {'config': KNOWN_HOSTS}
|
|
|
|
# wrong fingerprint
|
|
|
|
ret = self.run_function('ssh.check_known_host', arg,
|
|
|
|
**dict(kwargs, fingerprint=GITHUB_FINGERPRINT))
|
|
|
|
self.assertEqual(ret, 'exists')
|
|
|
|
# wrong keyfile
|
|
|
|
ret = self.run_function('ssh.check_known_host', arg,
|
|
|
|
**dict(kwargs, key=self.key))
|
|
|
|
self.assertEqual(ret, 'exists')
|
|
|
|
|
|
|
|
def test_rm_known_host(self):
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
|
|
|
ssh.rm_known_host
|
|
|
|
'''
|
2012-05-21 15:44:26 +00:00
|
|
|
shutil.copyfile(
|
2017-04-03 16:04:09 +00:00
|
|
|
os.path.join(FILES, 'ssh', 'known_hosts'),
|
2012-05-21 15:44:26 +00:00
|
|
|
KNOWN_HOSTS)
|
|
|
|
arg = ['root', 'github.com']
|
|
|
|
kwargs = {'config': KNOWN_HOSTS, 'key': self.key}
|
|
|
|
# before removal
|
|
|
|
ret = self.run_function('ssh.check_known_host', arg, **kwargs)
|
|
|
|
self.assertEqual(ret, 'exists')
|
|
|
|
# remove
|
|
|
|
self.run_function('ssh.rm_known_host', arg, config=KNOWN_HOSTS)
|
|
|
|
# after removal
|
|
|
|
ret = self.run_function('ssh.check_known_host', arg, **kwargs)
|
|
|
|
self.assertEqual(ret, 'add')
|
|
|
|
|
|
|
|
def test_set_known_host(self):
|
2012-06-04 23:22:43 +00:00
|
|
|
'''
|
|
|
|
ssh.set_known_host
|
|
|
|
'''
|
2012-05-21 15:44:26 +00:00
|
|
|
# add item
|
|
|
|
ret = self.run_function('ssh.set_known_host', ['root', 'github.com'],
|
|
|
|
config=KNOWN_HOSTS)
|
2013-08-13 23:35:58 +00:00
|
|
|
try:
|
|
|
|
self.assertEqual(ret['status'], 'updated')
|
|
|
|
self.assertEqual(ret['old'], None)
|
2017-09-13 04:54:10 +00:00
|
|
|
self.assertEqual(ret['new'][0]['fingerprint'], GITHUB_FINGERPRINT)
|
2013-08-13 23:35:58 +00:00
|
|
|
except AssertionError as exc:
|
|
|
|
raise AssertionError(
|
|
|
|
'AssertionError: {0}. Function returned: {1}'.format(
|
|
|
|
exc, ret
|
|
|
|
)
|
|
|
|
)
|
2012-05-21 15:44:26 +00:00
|
|
|
# check that item does exist
|
2017-09-13 04:54:10 +00:00
|
|
|
ret = self.run_function('ssh.get_known_host_entries', ['root', 'github.com'],
|
|
|
|
config=KNOWN_HOSTS)[0]
|
2013-08-13 23:35:58 +00:00
|
|
|
try:
|
|
|
|
self.assertEqual(ret['fingerprint'], GITHUB_FINGERPRINT)
|
|
|
|
except AssertionError as exc:
|
|
|
|
raise AssertionError(
|
|
|
|
'AssertionError: {0}. Function returned: {1}'.format(
|
|
|
|
exc, ret
|
|
|
|
)
|
|
|
|
)
|
2012-05-21 15:44:26 +00:00
|
|
|
# add the same item once again
|
|
|
|
ret = self.run_function('ssh.set_known_host', ['root', 'github.com'],
|
|
|
|
config=KNOWN_HOSTS)
|
2013-08-13 23:35:58 +00:00
|
|
|
try:
|
2015-02-25 22:27:03 +00:00
|
|
|
self.assertEqual(ret['status'], 'exists')
|
2013-08-13 23:35:58 +00:00
|
|
|
except AssertionError as exc:
|
|
|
|
raise AssertionError(
|
|
|
|
'AssertionError: {0}. Function returned: {1}'.format(
|
|
|
|
exc, ret
|
|
|
|
)
|
|
|
|
)
|