salt/tests/unit/test_master.py
2020-05-14 17:34:51 -07:00

661 lines
22 KiB
Python

# -*- coding: utf-8 -*-
from __future__ import absolute_import
import salt.config
import salt.master
from tests.support.helpers import slowTest
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
class TransportMethodsTest(TestCase):
def test_transport_methods(self):
class Foo(salt.master.TransportMethods):
expose_methods = ["bar"]
def bar(self):
pass
def bang(self):
pass
foo = Foo()
assert foo.get_method("bar") is not None
assert foo.get_method("bang") is None
def test_aes_funcs_white(self):
"""
Validate methods exposed on AESFuncs exist and are callable
"""
opts = salt.config.master_config(None)
aes_funcs = salt.master.AESFuncs(opts)
for name in aes_funcs.expose_methods:
func = getattr(aes_funcs, name, None)
assert callable(func)
def test_aes_funcs_black(self):
"""
Validate methods on AESFuncs that should not be called remotely
"""
opts = salt.config.master_config(None)
aes_funcs = salt.master.AESFuncs(opts)
# Any callable that should not explicitly be allowed should be added
# here.
blacklist_methods = [
"_AESFuncs__setup_fileserver",
"_AESFuncs__verify_load",
"_AESFuncs__verify_minion",
"_AESFuncs__verify_minion_publish",
"__class__",
"__delattr__",
"__dir__",
"__eq__",
"__format__",
"__ge__",
"__getattribute__",
"__gt__",
"__hash__",
"__init__",
"__init_subclass__",
"__le__",
"__lt__",
"__ne__",
"__new__",
"__reduce__",
"__reduce_ex__",
"__repr__",
"__setattr__",
"__sizeof__",
"__str__",
"__subclasshook__",
"get_method",
"run_func",
]
for name in dir(aes_funcs):
if name in aes_funcs.expose_methods:
continue
if not callable(getattr(aes_funcs, name)):
continue
assert name in blacklist_methods, name
def test_clear_funcs_white(self):
"""
Validate methods exposed on ClearFuncs exist and are callable
"""
opts = salt.config.master_config(None)
clear_funcs = salt.master.ClearFuncs(opts, {})
for name in clear_funcs.expose_methods:
func = getattr(clear_funcs, name, None)
assert callable(func)
def test_clear_funcs_black(self):
"""
Validate methods on ClearFuncs that should not be called remotely
"""
opts = salt.config.master_config(None)
clear_funcs = salt.master.ClearFuncs(opts, {})
blacklist_methods = [
"__class__",
"__delattr__",
"__dir__",
"__eq__",
"__format__",
"__ge__",
"__getattribute__",
"__gt__",
"__hash__",
"__init__",
"__init_subclass__",
"__le__",
"__lt__",
"__ne__",
"__new__",
"__reduce__",
"__reduce_ex__",
"__repr__",
"__setattr__",
"__sizeof__",
"__str__",
"__subclasshook__",
"_prep_auth_info",
"_prep_jid",
"_prep_pub",
"_send_pub",
"_send_ssh_pub",
"get_method",
]
for name in dir(clear_funcs):
if name in clear_funcs.expose_methods:
continue
if not callable(getattr(clear_funcs, name)):
continue
assert name in blacklist_methods, name
class ClearFuncsTestCase(TestCase):
"""
TestCase for salt.master.ClearFuncs class
"""
@classmethod
def setUpClass(cls):
opts = salt.config.master_config(None)
cls.clear_funcs = salt.master.ClearFuncs(opts, {})
@classmethod
def tearDownClass(cls):
del cls.clear_funcs
def test_get_method(self):
assert getattr(self.clear_funcs, "_send_pub", None) is not None
assert self.clear_funcs.get_method("_send_pub") is None
# runner tests
@slowTest
def test_runner_token_not_authenticated(self):
"""
Asserts that a TokenAuthenticationError is returned when the token can't authenticate.
"""
mock_ret = {
"error": {
"name": "TokenAuthenticationError",
"message": 'Authentication failure of type "token" occurred.',
}
}
ret = self.clear_funcs.runner({"token": "asdfasdfasdfasdf"})
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_runner_token_authorization_error(self):
"""
Asserts that a TokenAuthenticationError is returned when the token authenticates, but is
not authorized.
"""
token = "asdfasdfasdfasdf"
clear_load = {"token": token, "fun": "test.arg"}
mock_token = {"token": token, "eauth": "foo", "name": "test"}
mock_ret = {
"error": {
"name": "TokenAuthenticationError",
"message": 'Authentication failure of type "token" occurred '
"for user test.",
}
}
with patch(
"salt.auth.LoadAuth.authenticate_token", MagicMock(return_value=mock_token)
), patch("salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])):
ret = self.clear_funcs.runner(clear_load)
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_runner_token_salt_invocation_error(self):
"""
Asserts that a SaltInvocationError is returned when the token authenticates, but the
command is malformed.
"""
token = "asdfasdfasdfasdf"
clear_load = {"token": token, "fun": "badtestarg"}
mock_token = {"token": token, "eauth": "foo", "name": "test"}
mock_ret = {
"error": {
"name": "SaltInvocationError",
"message": "A command invocation error occurred: Check syntax.",
}
}
with patch(
"salt.auth.LoadAuth.authenticate_token", MagicMock(return_value=mock_token)
), patch(
"salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=["testing"])
):
ret = self.clear_funcs.runner(clear_load)
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_runner_eauth_not_authenticated(self):
"""
Asserts that an EauthAuthenticationError is returned when the user can't authenticate.
"""
mock_ret = {
"error": {
"name": "EauthAuthenticationError",
"message": 'Authentication failure of type "eauth" occurred for '
"user UNKNOWN.",
}
}
ret = self.clear_funcs.runner({"eauth": "foo"})
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_runner_eauth_authorization_error(self):
"""
Asserts that an EauthAuthenticationError is returned when the user authenticates, but is
not authorized.
"""
clear_load = {"eauth": "foo", "username": "test", "fun": "test.arg"}
mock_ret = {
"error": {
"name": "EauthAuthenticationError",
"message": 'Authentication failure of type "eauth" occurred for '
"user test.",
}
}
with patch(
"salt.auth.LoadAuth.authenticate_eauth", MagicMock(return_value=True)
), patch("salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])):
ret = self.clear_funcs.runner(clear_load)
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_runner_eauth_salt_invocation_error(self):
"""
Asserts that an EauthAuthenticationError is returned when the user authenticates, but the
command is malformed.
"""
clear_load = {"eauth": "foo", "username": "test", "fun": "bad.test.arg.func"}
mock_ret = {
"error": {
"name": "SaltInvocationError",
"message": "A command invocation error occurred: Check syntax.",
}
}
with patch(
"salt.auth.LoadAuth.authenticate_eauth", MagicMock(return_value=True)
), patch(
"salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=["testing"])
):
ret = self.clear_funcs.runner(clear_load)
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_runner_user_not_authenticated(self):
"""
Asserts that an UserAuthenticationError is returned when the user can't authenticate.
"""
mock_ret = {
"error": {
"name": "UserAuthenticationError",
"message": 'Authentication failure of type "user" occurred',
}
}
ret = self.clear_funcs.runner({})
self.assertDictEqual(mock_ret, ret)
# wheel tests
@slowTest
def test_wheel_token_not_authenticated(self):
"""
Asserts that a TokenAuthenticationError is returned when the token can't authenticate.
"""
mock_ret = {
"error": {
"name": "TokenAuthenticationError",
"message": 'Authentication failure of type "token" occurred.',
}
}
ret = self.clear_funcs.wheel({"token": "asdfasdfasdfasdf"})
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_wheel_token_authorization_error(self):
"""
Asserts that a TokenAuthenticationError is returned when the token authenticates, but is
not authorized.
"""
token = "asdfasdfasdfasdf"
clear_load = {"token": token, "fun": "test.arg"}
mock_token = {"token": token, "eauth": "foo", "name": "test"}
mock_ret = {
"error": {
"name": "TokenAuthenticationError",
"message": 'Authentication failure of type "token" occurred '
"for user test.",
}
}
with patch(
"salt.auth.LoadAuth.authenticate_token", MagicMock(return_value=mock_token)
), patch("salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])):
ret = self.clear_funcs.wheel(clear_load)
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_wheel_token_salt_invocation_error(self):
"""
Asserts that a SaltInvocationError is returned when the token authenticates, but the
command is malformed.
"""
token = "asdfasdfasdfasdf"
clear_load = {"token": token, "fun": "badtestarg"}
mock_token = {"token": token, "eauth": "foo", "name": "test"}
mock_ret = {
"error": {
"name": "SaltInvocationError",
"message": "A command invocation error occurred: Check syntax.",
}
}
with patch(
"salt.auth.LoadAuth.authenticate_token", MagicMock(return_value=mock_token)
), patch(
"salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=["testing"])
):
ret = self.clear_funcs.wheel(clear_load)
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_wheel_eauth_not_authenticated(self):
"""
Asserts that an EauthAuthenticationError is returned when the user can't authenticate.
"""
mock_ret = {
"error": {
"name": "EauthAuthenticationError",
"message": 'Authentication failure of type "eauth" occurred for '
"user UNKNOWN.",
}
}
ret = self.clear_funcs.wheel({"eauth": "foo"})
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_wheel_eauth_authorization_error(self):
"""
Asserts that an EauthAuthenticationError is returned when the user authenticates, but is
not authorized.
"""
clear_load = {"eauth": "foo", "username": "test", "fun": "test.arg"}
mock_ret = {
"error": {
"name": "EauthAuthenticationError",
"message": 'Authentication failure of type "eauth" occurred for '
"user test.",
}
}
with patch(
"salt.auth.LoadAuth.authenticate_eauth", MagicMock(return_value=True)
), patch("salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])):
ret = self.clear_funcs.wheel(clear_load)
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_wheel_eauth_salt_invocation_error(self):
"""
Asserts that an EauthAuthenticationError is returned when the user authenticates, but the
command is malformed.
"""
clear_load = {"eauth": "foo", "username": "test", "fun": "bad.test.arg.func"}
mock_ret = {
"error": {
"name": "SaltInvocationError",
"message": "A command invocation error occurred: Check syntax.",
}
}
with patch(
"salt.auth.LoadAuth.authenticate_eauth", MagicMock(return_value=True)
), patch(
"salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=["testing"])
):
ret = self.clear_funcs.wheel(clear_load)
self.assertDictEqual(mock_ret, ret)
@slowTest
def test_wheel_user_not_authenticated(self):
"""
Asserts that an UserAuthenticationError is returned when the user can't authenticate.
"""
mock_ret = {
"error": {
"name": "UserAuthenticationError",
"message": 'Authentication failure of type "user" occurred',
}
}
ret = self.clear_funcs.wheel({})
self.assertDictEqual(mock_ret, ret)
# publish tests
@slowTest
def test_publish_user_is_blacklisted(self):
"""
Asserts that an AuthorizationError is returned when the user has been blacklisted.
"""
mock_ret = {
"error": {
"name": "AuthorizationError",
"message": "Authorization error occurred.",
}
}
with patch(
"salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=True)
):
self.assertEqual(
mock_ret, self.clear_funcs.publish({"user": "foo", "fun": "test.arg"})
)
@slowTest
def test_publish_cmd_blacklisted(self):
"""
Asserts that an AuthorizationError is returned when the command has been blacklisted.
"""
mock_ret = {
"error": {
"name": "AuthorizationError",
"message": "Authorization error occurred.",
}
}
with patch(
"salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=True)
):
self.assertEqual(
mock_ret, self.clear_funcs.publish({"user": "foo", "fun": "test.arg"})
)
@slowTest
def test_publish_token_not_authenticated(self):
"""
Asserts that an AuthenticationError is returned when the token can't authenticate.
"""
mock_ret = {
"error": {
"name": "AuthenticationError",
"message": "Authentication error occurred.",
}
}
load = {
"user": "foo",
"fun": "test.arg",
"tgt": "test_minion",
"kwargs": {"token": "asdfasdfasdfasdf"},
}
with patch(
"salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
):
self.assertEqual(mock_ret, self.clear_funcs.publish(load))
@slowTest
def test_publish_token_authorization_error(self):
"""
Asserts that an AuthorizationError is returned when the token authenticates, but is not
authorized.
"""
token = "asdfasdfasdfasdf"
load = {
"user": "foo",
"fun": "test.arg",
"tgt": "test_minion",
"arg": "bar",
"kwargs": {"token": token},
}
mock_token = {"token": token, "eauth": "foo", "name": "test"}
mock_ret = {
"error": {
"name": "AuthorizationError",
"message": "Authorization error occurred.",
}
}
with patch(
"salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.auth.LoadAuth.authenticate_token", MagicMock(return_value=mock_token)
), patch(
"salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])
):
self.assertEqual(mock_ret, self.clear_funcs.publish(load))
@slowTest
def test_publish_eauth_not_authenticated(self):
"""
Asserts that an AuthenticationError is returned when the user can't authenticate.
"""
load = {
"user": "test",
"fun": "test.arg",
"tgt": "test_minion",
"kwargs": {"eauth": "foo"},
}
mock_ret = {
"error": {
"name": "AuthenticationError",
"message": "Authentication error occurred.",
}
}
with patch(
"salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
):
self.assertEqual(mock_ret, self.clear_funcs.publish(load))
@slowTest
def test_publish_eauth_authorization_error(self):
"""
Asserts that an AuthorizationError is returned when the user authenticates, but is not
authorized.
"""
load = {
"user": "test",
"fun": "test.arg",
"tgt": "test_minion",
"kwargs": {"eauth": "foo"},
"arg": "bar",
}
mock_ret = {
"error": {
"name": "AuthorizationError",
"message": "Authorization error occurred.",
}
}
with patch(
"salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.auth.LoadAuth.authenticate_eauth", MagicMock(return_value=True)
), patch(
"salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])
):
self.assertEqual(mock_ret, self.clear_funcs.publish(load))
@slowTest
def test_publish_user_not_authenticated(self):
"""
Asserts that an AuthenticationError is returned when the user can't authenticate.
"""
load = {"user": "test", "fun": "test.arg", "tgt": "test_minion"}
mock_ret = {
"error": {
"name": "AuthenticationError",
"message": "Authentication error occurred.",
}
}
with patch(
"salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
):
self.assertEqual(mock_ret, self.clear_funcs.publish(load))
@slowTest
def test_publish_user_authenticated_missing_auth_list(self):
"""
Asserts that an AuthenticationError is returned when the user has an effective user id and is
authenticated, but the auth_list is empty.
"""
load = {
"user": "test",
"fun": "test.arg",
"tgt": "test_minion",
"kwargs": {"user": "test"},
"arg": "foo",
}
mock_ret = {
"error": {
"name": "AuthenticationError",
"message": "Authentication error occurred.",
}
}
with patch(
"salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.auth.LoadAuth.authenticate_key",
MagicMock(return_value="fake-user-key"),
), patch(
"salt.utils.master.get_values_of_matching_keys", MagicMock(return_value=[])
):
self.assertEqual(mock_ret, self.clear_funcs.publish(load))
@slowTest
def test_publish_user_authorization_error(self):
"""
Asserts that an AuthorizationError is returned when the user authenticates, but is not
authorized.
"""
load = {
"user": "test",
"fun": "test.arg",
"tgt": "test_minion",
"kwargs": {"user": "test"},
"arg": "foo",
}
mock_ret = {
"error": {
"name": "AuthorizationError",
"message": "Authorization error occurred.",
}
}
with patch(
"salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
), patch(
"salt.auth.LoadAuth.authenticate_key",
MagicMock(return_value="fake-user-key"),
), patch(
"salt.utils.master.get_values_of_matching_keys",
MagicMock(return_value=["test"]),
), patch(
"salt.utils.minions.CkMinions.auth_check", MagicMock(return_value=False)
):
self.assertEqual(mock_ret, self.clear_funcs.publish(load))