123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990 |
- # -*- coding: utf-8 -*-
- from __future__ import absolute_import, print_function, unicode_literals
- import io
- import os
- import stat
- from functools import wraps
- import salt.config
- import salt.daemons.masterapi as masterapi
- import salt.utils.platform
- from tests.support.helpers import slowTest
- from tests.support.mock import MagicMock, patch
- from tests.support.runtests import RUNTIME_VARS
- from tests.support.unit import TestCase
- def gen_permissions(owner="", group="", others=""):
- """
- Helper method to generate file permission bits
- Usage: gen_permissions('rw', 'r', 'r')
- """
- ret = 0
- for c in owner:
- ret |= getattr(stat, "S_I{}USR".format(c.upper()), 0)
- for c in group:
- ret |= getattr(stat, "S_I{}GRP".format(c.upper()), 0)
- for c in others:
- ret |= getattr(stat, "S_I{}OTH".format(c.upper()), 0)
- return ret
- def patch_check_permissions(uid=1, groups=None, is_windows=False, permissive_pki=False):
- if not groups:
- groups = [uid]
- def decorator(func):
- @wraps(func)
- def wrapper(self):
- self.auto_key.opts["permissive_pki_access"] = permissive_pki
- if salt.utils.platform.is_windows():
- with patch(
- "salt.utils.platform.is_windows", MagicMock(return_value=True)
- ):
- func(self)
- else:
- with patch("os.stat", self.os_stat_mock), patch(
- "os.getuid", MagicMock(return_value=uid)
- ), patch(
- "salt.utils.user.get_gid_list", MagicMock(return_value=groups)
- ), patch(
- "salt.utils.platform.is_windows", MagicMock(return_value=is_windows)
- ):
- func(self)
- return wrapper
- return decorator
- class AutoKeyTest(TestCase):
- """
- Tests for the salt.daemons.masterapi.AutoKey class
- """
- def setUp(self):
- opts = salt.config.master_config(None)
- opts["user"] = "test_user"
- self.auto_key = masterapi.AutoKey(opts)
- self.stats = {}
- def os_stat_mock(self, filename):
- fmode = MagicMock()
- fstats = self.stats.get(filename, {})
- fmode.st_mode = fstats.get("mode", 0)
- fmode.st_gid = fstats.get("gid", 0)
- return fmode
- @patch_check_permissions(uid=0, is_windows=True)
- def test_check_permissions_windows(self):
- """
- Assert that all files are accepted on windows
- """
- self.stats["testfile"] = {
- "mode": gen_permissions("rwx", "rwx", "rwx"),
- "gid": 2,
- }
- self.assertTrue(self.auto_key.check_permissions("testfile"))
- @patch_check_permissions(permissive_pki=True)
- def test_check_permissions_others_can_write(self):
- """
- Assert that no file is accepted, when others can write to it
- """
- self.stats["testfile"] = {"mode": gen_permissions("", "", "w"), "gid": 1}
- if salt.utils.platform.is_windows():
- self.assertTrue(self.auto_key.check_permissions("testfile"))
- else:
- self.assertFalse(self.auto_key.check_permissions("testfile"))
- @patch_check_permissions()
- def test_check_permissions_group_can_write_not_permissive(self):
- """
- Assert that a file is accepted, when group can write to it and
- permissive_pki_access=False
- """
- self.stats["testfile"] = {"mode": gen_permissions("w", "w", ""), "gid": 1}
- if salt.utils.platform.is_windows():
- self.assertTrue(self.auto_key.check_permissions("testfile"))
- else:
- self.assertFalse(self.auto_key.check_permissions("testfile"))
- @patch_check_permissions(permissive_pki=True)
- def test_check_permissions_group_can_write_permissive(self):
- """
- Assert that a file is accepted, when group can write to it and
- permissive_pki_access=True
- """
- self.stats["testfile"] = {"mode": gen_permissions("w", "w", ""), "gid": 1}
- self.assertTrue(self.auto_key.check_permissions("testfile"))
- @patch_check_permissions(uid=0, permissive_pki=True)
- def test_check_permissions_group_can_write_permissive_root_in_group(self):
- """
- Assert that a file is accepted, when group can write to it,
- permissive_pki_access=False, salt is root and in the file owning group
- """
- self.stats["testfile"] = {"mode": gen_permissions("w", "w", ""), "gid": 0}
- self.assertTrue(self.auto_key.check_permissions("testfile"))
- @patch_check_permissions(uid=0, permissive_pki=True)
- def test_check_permissions_group_can_write_permissive_root_not_in_group(self):
- """
- Assert that no file is accepted, when group can write to it,
- permissive_pki_access=False, salt is root and **not** in the file owning
- group
- """
- self.stats["testfile"] = {"mode": gen_permissions("w", "w", ""), "gid": 1}
- if salt.utils.platform.is_windows():
- self.assertTrue(self.auto_key.check_permissions("testfile"))
- else:
- self.assertFalse(self.auto_key.check_permissions("testfile"))
- @patch_check_permissions()
- def test_check_permissions_only_owner_can_write(self):
- """
- Assert that a file is accepted, when only the owner can write to it
- """
- self.stats["testfile"] = {"mode": gen_permissions("w", "", ""), "gid": 1}
- self.assertTrue(self.auto_key.check_permissions("testfile"))
- @patch_check_permissions(uid=0)
- def test_check_permissions_only_owner_can_write_root(self):
- """
- Assert that a file is accepted, when only the owner can write to it and salt is root
- """
- self.stats["testfile"] = {"mode": gen_permissions("w", "", ""), "gid": 0}
- self.assertTrue(self.auto_key.check_permissions("testfile"))
- def _test_check_autosign_grains(
- self,
- test_func,
- file_content="test_value",
- file_name="test_grain",
- autosign_grains_dir="test_dir",
- permissions_ret=True,
- ):
- """
- Helper function for testing autosign_grains().
- Patches ``os.walk`` to return only ``file_name`` and ``salt.utils.files.fopen`` to open a
- mock file with ``file_content`` as content. Optionally sets ``opts`` values.
- Then executes test_func. The ``os.walk`` and ``salt.utils.files.fopen`` mock objects
- are passed to the function as arguments.
- """
- if autosign_grains_dir:
- self.auto_key.opts["autosign_grains_dir"] = autosign_grains_dir
- mock_file = io.StringIO(file_content)
- mock_dirs = [(None, None, [file_name])]
- with patch("os.walk", MagicMock(return_value=mock_dirs)) as mock_walk, patch(
- "salt.utils.files.fopen", MagicMock(return_value=mock_file)
- ) as mock_open, patch(
- "salt.daemons.masterapi.AutoKey.check_permissions",
- MagicMock(return_value=permissions_ret),
- ) as mock_permissions:
- test_func(mock_walk, mock_open, mock_permissions)
- def test_check_autosign_grains_no_grains(self):
- """
- Asserts that autosigning from grains fails when no grain values are passed.
- """
- def test_func(mock_walk, mock_open, mock_permissions):
- self.assertFalse(self.auto_key.check_autosign_grains(None))
- self.assertEqual(mock_walk.call_count, 0)
- self.assertEqual(mock_open.call_count, 0)
- self.assertEqual(mock_permissions.call_count, 0)
- self.assertFalse(self.auto_key.check_autosign_grains({}))
- self.assertEqual(mock_walk.call_count, 0)
- self.assertEqual(mock_open.call_count, 0)
- self.assertEqual(mock_permissions.call_count, 0)
- self._test_check_autosign_grains(test_func)
- def test_check_autosign_grains_no_autosign_grains_dir(self):
- """
- Asserts that autosigning from grains fails when the \'autosign_grains_dir\' config option
- is undefined.
- """
- def test_func(mock_walk, mock_open, mock_permissions):
- self.assertFalse(
- self.auto_key.check_autosign_grains({"test_grain": "test_value"})
- )
- self.assertEqual(mock_walk.call_count, 0)
- self.assertEqual(mock_open.call_count, 0)
- self.assertEqual(mock_permissions.call_count, 0)
- self._test_check_autosign_grains(test_func, autosign_grains_dir=None)
- def test_check_autosign_grains_accept(self):
- """
- Asserts that autosigning from grains passes when a matching grain value is in an
- autosign_grain file.
- """
- def test_func(*args):
- self.assertTrue(
- self.auto_key.check_autosign_grains({"test_grain": "test_value"})
- )
- file_content = "#test_ignore\ntest_value"
- self._test_check_autosign_grains(test_func, file_content=file_content)
- def test_check_autosign_grains_accept_not(self):
- """
- Asserts that autosigning from grains fails when the grain value is not in the
- autosign_grain files.
- """
- def test_func(*args):
- self.assertFalse(
- self.auto_key.check_autosign_grains({"test_grain": "test_invalid"})
- )
- file_content = "#test_invalid\ntest_value"
- self._test_check_autosign_grains(test_func, file_content=file_content)
- def test_check_autosign_grains_invalid_file_permissions(self):
- """
- Asserts that autosigning from grains fails when the grain file has the wrong permissions.
- """
- def test_func(*args):
- self.assertFalse(
- self.auto_key.check_autosign_grains({"test_grain": "test_value"})
- )
- file_content = "#test_ignore\ntest_value"
- self._test_check_autosign_grains(
- test_func, file_content=file_content, permissions_ret=False
- )
- class LocalFuncsTestCase(TestCase):
- """
- TestCase for salt.daemons.masterapi.LocalFuncs class
- """
- def setUp(self):
- opts = salt.config.master_config(None)
- self.local_funcs = masterapi.LocalFuncs(opts, "test-key")
- # 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.local_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"
- load = {"token": token, "fun": "test.arg", "kwarg": {}}
- 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.local_funcs.runner(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"
- load = {"token": token, "fun": "badtestarg", "kwarg": {}}
- 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.local_funcs.runner(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.local_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.
- """
- load = {"eauth": "foo", "username": "test", "fun": "test.arg", "kwarg": {}}
- 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.local_funcs.runner(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.
- """
- load = {
- "eauth": "foo",
- "username": "test",
- "fun": "bad.test.arg.func",
- "kwarg": {},
- }
- 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.local_funcs.runner(load)
- 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.local_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"
- load = {"token": token, "fun": "test.arg", "kwarg": {}}
- 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.local_funcs.wheel(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"
- load = {"token": token, "fun": "badtestarg", "kwarg": {}}
- 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.local_funcs.wheel(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.local_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.
- """
- load = {"eauth": "foo", "username": "test", "fun": "test.arg", "kwarg": {}}
- 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.local_funcs.wheel(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.
- """
- load = {
- "eauth": "foo",
- "username": "test",
- "fun": "bad.test.arg.func",
- "kwarg": {},
- }
- 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.local_funcs.wheel(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 for '
- "user UNKNOWN.",
- }
- }
- ret = self.local_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.local_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.local_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.
- """
- load = {
- "user": "foo",
- "fun": "test.arg",
- "tgt": "test_minion",
- "kwargs": {"token": "asdfasdfasdfasdf"},
- }
- 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.local_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.local_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.local_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.local_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.local_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.local_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.local_funcs.publish(load))
- class FakeCache(object):
- def __init__(self):
- self.data = {}
- def store(self, bank, key, value):
- self.data[bank, key] = value
- def fetch(self, bank, key):
- return self.data[bank, key]
- class RemoteFuncsTestCase(TestCase):
- """
- TestCase for salt.daemons.masterapi.RemoteFuncs class
- """
- def setUp(self):
- opts = salt.config.master_config(
- os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "master")
- )
- self.funcs = masterapi.RemoteFuncs(opts)
- self.funcs.cache = FakeCache()
- @slowTest
- def test_mine_get(self, tgt_type_key="tgt_type"):
- """
- Asserts that ``mine_get`` gives the expected results.
- Actually this only tests that:
- - the correct check minions method is called
- - the correct cache key is subsequently used
- """
- self.funcs.cache.store(
- "minions/webserver", "mine", dict(ip_addr="2001:db8::1:3")
- )
- with patch(
- "salt.utils.minions.CkMinions._check_compound_minions",
- MagicMock(return_value=(dict(minions=["webserver"], missing=[]))),
- ):
- ret = self.funcs._mine_get(
- {
- "id": "requester_minion",
- "tgt": "G@roles:web",
- "fun": "ip_addr",
- tgt_type_key: "compound",
- }
- )
- self.assertDictEqual(ret, dict(webserver="2001:db8::1:3"))
- @slowTest
- def test_mine_get_pre_nitrogen_compat(self):
- """
- Asserts that pre-Nitrogen API key ``expr_form`` is still accepted.
- This is what minions before Nitrogen would issue.
- """
- self.test_mine_get(tgt_type_key="expr_form")
- @slowTest
- def test_mine_get_dict_str(self, tgt_type_key="tgt_type"):
- """
- Asserts that ``mine_get`` gives the expected results when request
- is a comma-separated list.
- Actually this only tests that:
- - the correct check minions method is called
- - the correct cache key is subsequently used
- """
- self.funcs.cache.store(
- "minions/webserver",
- "mine",
- dict(ip_addr="2001:db8::1:3", ip4_addr="127.0.0.1"),
- )
- with patch(
- "salt.utils.minions.CkMinions._check_compound_minions",
- MagicMock(return_value=(dict(minions=["webserver"], missing=[]))),
- ):
- ret = self.funcs._mine_get(
- {
- "id": "requester_minion",
- "tgt": "G@roles:web",
- "fun": "ip_addr,ip4_addr",
- tgt_type_key: "compound",
- }
- )
- self.assertDictEqual(
- ret,
- dict(
- ip_addr=dict(webserver="2001:db8::1:3"),
- ip4_addr=dict(webserver="127.0.0.1"),
- ),
- )
- @slowTest
- def test_mine_get_dict_list(self, tgt_type_key="tgt_type"):
- """
- Asserts that ``mine_get`` gives the expected results when request
- is a list.
- Actually this only tests that:
- - the correct check minions method is called
- - the correct cache key is subsequently used
- """
- self.funcs.cache.store(
- "minions/webserver",
- "mine",
- dict(ip_addr="2001:db8::1:3", ip4_addr="127.0.0.1"),
- )
- with patch(
- "salt.utils.minions.CkMinions._check_compound_minions",
- MagicMock(return_value=(dict(minions=["webserver"], missing=[]))),
- ):
- ret = self.funcs._mine_get(
- {
- "id": "requester_minion",
- "tgt": "G@roles:web",
- "fun": ["ip_addr", "ip4_addr"],
- tgt_type_key: "compound",
- }
- )
- self.assertDictEqual(
- ret,
- dict(
- ip_addr=dict(webserver="2001:db8::1:3"),
- ip4_addr=dict(webserver="127.0.0.1"),
- ),
- )
- @slowTest
- def test_mine_get_acl_allowed(self):
- """
- Asserts that ``mine_get`` gives the expected results when this is allowed
- in the client-side ACL that was stored in the mine data.
- """
- self.funcs.cache.store(
- "minions/webserver",
- "mine",
- {
- "ip_addr": {
- salt.utils.mine.MINE_ITEM_ACL_DATA: "2001:db8::1:4",
- salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
- "allow_tgt": "requester_minion",
- "allow_tgt_type": "glob",
- },
- },
- )
- # The glob check is for the resolution of the allow_tgt
- # The compound check is for the resolution of the tgt in the mine_get request.
- with patch(
- "salt.utils.minions.CkMinions._check_glob_minions",
- MagicMock(return_value={"minions": ["requester_minion"], "missing": []}),
- ), patch(
- "salt.utils.minions.CkMinions._check_compound_minions",
- MagicMock(return_value={"minions": ["webserver"], "missing": []}),
- ):
- ret = self.funcs._mine_get(
- {
- "id": "requester_minion",
- "tgt": "anything",
- "tgt_type": "compound",
- "fun": ["ip_addr"],
- }
- )
- self.assertDictEqual(ret, {"ip_addr": {"webserver": "2001:db8::1:4"}})
- @slowTest
- def test_mine_get_acl_rejected(self):
- """
- Asserts that ``mine_get`` gives the expected results when this is rejected
- in the client-side ACL that was stored in the mine data. This results in
- no data being sent back (just as if the entry wouldn't exist).
- """
- self.funcs.cache.store(
- "minions/webserver",
- "mine",
- {
- "ip_addr": {
- salt.utils.mine.MINE_ITEM_ACL_DATA: "2001:db8::1:4",
- salt.utils.mine.MINE_ITEM_ACL_ID: salt.utils.mine.MINE_ITEM_ACL_VERSION,
- "allow_tgt": "not_requester_minion",
- "allow_tgt_type": "glob",
- }
- },
- )
- # The glob check is for the resolution of the allow_tgt
- # The compound check is for the resolution of the tgt in the mine_get request.
- with patch(
- "salt.utils.minions.CkMinions._check_glob_minions",
- MagicMock(
- return_value={"minions": ["not_requester_minion"], "missing": []}
- ),
- ), patch(
- "salt.utils.minions.CkMinions._check_compound_minions",
- MagicMock(return_value={"minions": ["webserver"], "missing": []}),
- ):
- ret = self.funcs._mine_get(
- {
- "id": "requester_minion",
- "tgt": "anything",
- "tgt_type": "compound",
- "fun": ["ip_addr"],
- }
- )
- self.assertDictEqual(ret, {})
|