test_master.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. # -*- coding: utf-8 -*-
  2. # Import Python libs
  3. from __future__ import absolute_import
  4. import pytest
  5. # Import Salt libs
  6. import salt.config
  7. import salt.master
  8. from tests.support.mock import MagicMock, patch
  9. # Import Salt Testing Libs
  10. from tests.support.unit import TestCase
  11. class ClearFuncsTestCase(TestCase):
  12. """
  13. TestCase for salt.master.ClearFuncs class
  14. """
  15. @classmethod
  16. def setUpClass(cls):
  17. opts = salt.config.master_config(None)
  18. cls.clear_funcs = salt.master.ClearFuncs(opts, {})
  19. @classmethod
  20. def tearDownClass(cls):
  21. del cls.clear_funcs
  22. # runner tests
  23. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  24. def test_runner_token_not_authenticated(self):
  25. """
  26. Asserts that a TokenAuthenticationError is returned when the token can't authenticate.
  27. """
  28. mock_ret = {
  29. "error": {
  30. "name": "TokenAuthenticationError",
  31. "message": 'Authentication failure of type "token" occurred.',
  32. }
  33. }
  34. ret = self.clear_funcs.runner({"token": "asdfasdfasdfasdf"})
  35. self.assertDictEqual(mock_ret, ret)
  36. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  37. def test_runner_token_authorization_error(self):
  38. """
  39. Asserts that a TokenAuthenticationError is returned when the token authenticates, but is
  40. not authorized.
  41. """
  42. token = "asdfasdfasdfasdf"
  43. clear_load = {"token": token, "fun": "test.arg"}
  44. mock_token = {"token": token, "eauth": "foo", "name": "test"}
  45. mock_ret = {
  46. "error": {
  47. "name": "TokenAuthenticationError",
  48. "message": 'Authentication failure of type "token" occurred '
  49. "for user test.",
  50. }
  51. }
  52. with patch(
  53. "salt.auth.LoadAuth.authenticate_token", MagicMock(return_value=mock_token)
  54. ), patch("salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])):
  55. ret = self.clear_funcs.runner(clear_load)
  56. self.assertDictEqual(mock_ret, ret)
  57. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  58. def test_runner_token_salt_invocation_error(self):
  59. """
  60. Asserts that a SaltInvocationError is returned when the token authenticates, but the
  61. command is malformed.
  62. """
  63. token = "asdfasdfasdfasdf"
  64. clear_load = {"token": token, "fun": "badtestarg"}
  65. mock_token = {"token": token, "eauth": "foo", "name": "test"}
  66. mock_ret = {
  67. "error": {
  68. "name": "SaltInvocationError",
  69. "message": "A command invocation error occurred: Check syntax.",
  70. }
  71. }
  72. with patch(
  73. "salt.auth.LoadAuth.authenticate_token", MagicMock(return_value=mock_token)
  74. ), patch(
  75. "salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=["testing"])
  76. ):
  77. ret = self.clear_funcs.runner(clear_load)
  78. self.assertDictEqual(mock_ret, ret)
  79. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  80. def test_runner_eauth_not_authenticated(self):
  81. """
  82. Asserts that an EauthAuthenticationError is returned when the user can't authenticate.
  83. """
  84. mock_ret = {
  85. "error": {
  86. "name": "EauthAuthenticationError",
  87. "message": 'Authentication failure of type "eauth" occurred for '
  88. "user UNKNOWN.",
  89. }
  90. }
  91. ret = self.clear_funcs.runner({"eauth": "foo"})
  92. self.assertDictEqual(mock_ret, ret)
  93. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  94. def test_runner_eauth_authorization_error(self):
  95. """
  96. Asserts that an EauthAuthenticationError is returned when the user authenticates, but is
  97. not authorized.
  98. """
  99. clear_load = {"eauth": "foo", "username": "test", "fun": "test.arg"}
  100. mock_ret = {
  101. "error": {
  102. "name": "EauthAuthenticationError",
  103. "message": 'Authentication failure of type "eauth" occurred for '
  104. "user test.",
  105. }
  106. }
  107. with patch(
  108. "salt.auth.LoadAuth.authenticate_eauth", MagicMock(return_value=True)
  109. ), patch("salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])):
  110. ret = self.clear_funcs.runner(clear_load)
  111. self.assertDictEqual(mock_ret, ret)
  112. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  113. def test_runner_eauth_salt_invocation_error(self):
  114. """
  115. Asserts that an EauthAuthenticationError is returned when the user authenticates, but the
  116. command is malformed.
  117. """
  118. clear_load = {"eauth": "foo", "username": "test", "fun": "bad.test.arg.func"}
  119. mock_ret = {
  120. "error": {
  121. "name": "SaltInvocationError",
  122. "message": "A command invocation error occurred: Check syntax.",
  123. }
  124. }
  125. with patch(
  126. "salt.auth.LoadAuth.authenticate_eauth", MagicMock(return_value=True)
  127. ), patch(
  128. "salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=["testing"])
  129. ):
  130. ret = self.clear_funcs.runner(clear_load)
  131. self.assertDictEqual(mock_ret, ret)
  132. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  133. def test_runner_user_not_authenticated(self):
  134. """
  135. Asserts that an UserAuthenticationError is returned when the user can't authenticate.
  136. """
  137. mock_ret = {
  138. "error": {
  139. "name": "UserAuthenticationError",
  140. "message": 'Authentication failure of type "user" occurred',
  141. }
  142. }
  143. ret = self.clear_funcs.runner({})
  144. self.assertDictEqual(mock_ret, ret)
  145. # wheel tests
  146. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  147. def test_wheel_token_not_authenticated(self):
  148. """
  149. Asserts that a TokenAuthenticationError is returned when the token can't authenticate.
  150. """
  151. mock_ret = {
  152. "error": {
  153. "name": "TokenAuthenticationError",
  154. "message": 'Authentication failure of type "token" occurred.',
  155. }
  156. }
  157. ret = self.clear_funcs.wheel({"token": "asdfasdfasdfasdf"})
  158. self.assertDictEqual(mock_ret, ret)
  159. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  160. def test_wheel_token_authorization_error(self):
  161. """
  162. Asserts that a TokenAuthenticationError is returned when the token authenticates, but is
  163. not authorized.
  164. """
  165. token = "asdfasdfasdfasdf"
  166. clear_load = {"token": token, "fun": "test.arg"}
  167. mock_token = {"token": token, "eauth": "foo", "name": "test"}
  168. mock_ret = {
  169. "error": {
  170. "name": "TokenAuthenticationError",
  171. "message": 'Authentication failure of type "token" occurred '
  172. "for user test.",
  173. }
  174. }
  175. with patch(
  176. "salt.auth.LoadAuth.authenticate_token", MagicMock(return_value=mock_token)
  177. ), patch("salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])):
  178. ret = self.clear_funcs.wheel(clear_load)
  179. self.assertDictEqual(mock_ret, ret)
  180. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  181. def test_wheel_token_salt_invocation_error(self):
  182. """
  183. Asserts that a SaltInvocationError is returned when the token authenticates, but the
  184. command is malformed.
  185. """
  186. token = "asdfasdfasdfasdf"
  187. clear_load = {"token": token, "fun": "badtestarg"}
  188. mock_token = {"token": token, "eauth": "foo", "name": "test"}
  189. mock_ret = {
  190. "error": {
  191. "name": "SaltInvocationError",
  192. "message": "A command invocation error occurred: Check syntax.",
  193. }
  194. }
  195. with patch(
  196. "salt.auth.LoadAuth.authenticate_token", MagicMock(return_value=mock_token)
  197. ), patch(
  198. "salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=["testing"])
  199. ):
  200. ret = self.clear_funcs.wheel(clear_load)
  201. self.assertDictEqual(mock_ret, ret)
  202. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  203. def test_wheel_eauth_not_authenticated(self):
  204. """
  205. Asserts that an EauthAuthenticationError is returned when the user can't authenticate.
  206. """
  207. mock_ret = {
  208. "error": {
  209. "name": "EauthAuthenticationError",
  210. "message": 'Authentication failure of type "eauth" occurred for '
  211. "user UNKNOWN.",
  212. }
  213. }
  214. ret = self.clear_funcs.wheel({"eauth": "foo"})
  215. self.assertDictEqual(mock_ret, ret)
  216. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  217. def test_wheel_eauth_authorization_error(self):
  218. """
  219. Asserts that an EauthAuthenticationError is returned when the user authenticates, but is
  220. not authorized.
  221. """
  222. clear_load = {"eauth": "foo", "username": "test", "fun": "test.arg"}
  223. mock_ret = {
  224. "error": {
  225. "name": "EauthAuthenticationError",
  226. "message": 'Authentication failure of type "eauth" occurred for '
  227. "user test.",
  228. }
  229. }
  230. with patch(
  231. "salt.auth.LoadAuth.authenticate_eauth", MagicMock(return_value=True)
  232. ), patch("salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])):
  233. ret = self.clear_funcs.wheel(clear_load)
  234. self.assertDictEqual(mock_ret, ret)
  235. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  236. def test_wheel_eauth_salt_invocation_error(self):
  237. """
  238. Asserts that an EauthAuthenticationError is returned when the user authenticates, but the
  239. command is malformed.
  240. """
  241. clear_load = {"eauth": "foo", "username": "test", "fun": "bad.test.arg.func"}
  242. mock_ret = {
  243. "error": {
  244. "name": "SaltInvocationError",
  245. "message": "A command invocation error occurred: Check syntax.",
  246. }
  247. }
  248. with patch(
  249. "salt.auth.LoadAuth.authenticate_eauth", MagicMock(return_value=True)
  250. ), patch(
  251. "salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=["testing"])
  252. ):
  253. ret = self.clear_funcs.wheel(clear_load)
  254. self.assertDictEqual(mock_ret, ret)
  255. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  256. def test_wheel_user_not_authenticated(self):
  257. """
  258. Asserts that an UserAuthenticationError is returned when the user can't authenticate.
  259. """
  260. mock_ret = {
  261. "error": {
  262. "name": "UserAuthenticationError",
  263. "message": 'Authentication failure of type "user" occurred',
  264. }
  265. }
  266. ret = self.clear_funcs.wheel({})
  267. self.assertDictEqual(mock_ret, ret)
  268. # publish tests
  269. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  270. def test_publish_user_is_blacklisted(self):
  271. """
  272. Asserts that an AuthorizationError is returned when the user has been blacklisted.
  273. """
  274. mock_ret = {
  275. "error": {
  276. "name": "AuthorizationError",
  277. "message": "Authorization error occurred.",
  278. }
  279. }
  280. with patch(
  281. "salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=True)
  282. ):
  283. self.assertEqual(
  284. mock_ret, self.clear_funcs.publish({"user": "foo", "fun": "test.arg"})
  285. )
  286. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  287. def test_publish_cmd_blacklisted(self):
  288. """
  289. Asserts that an AuthorizationError is returned when the command has been blacklisted.
  290. """
  291. mock_ret = {
  292. "error": {
  293. "name": "AuthorizationError",
  294. "message": "Authorization error occurred.",
  295. }
  296. }
  297. with patch(
  298. "salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
  299. ), patch(
  300. "salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=True)
  301. ):
  302. self.assertEqual(
  303. mock_ret, self.clear_funcs.publish({"user": "foo", "fun": "test.arg"})
  304. )
  305. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  306. def test_publish_token_not_authenticated(self):
  307. """
  308. Asserts that an AuthenticationError is returned when the token can't authenticate.
  309. """
  310. mock_ret = {
  311. "error": {
  312. "name": "AuthenticationError",
  313. "message": "Authentication error occurred.",
  314. }
  315. }
  316. load = {
  317. "user": "foo",
  318. "fun": "test.arg",
  319. "tgt": "test_minion",
  320. "kwargs": {"token": "asdfasdfasdfasdf"},
  321. }
  322. with patch(
  323. "salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
  324. ), patch(
  325. "salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
  326. ):
  327. self.assertEqual(mock_ret, self.clear_funcs.publish(load))
  328. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  329. def test_publish_token_authorization_error(self):
  330. """
  331. Asserts that an AuthorizationError is returned when the token authenticates, but is not
  332. authorized.
  333. """
  334. token = "asdfasdfasdfasdf"
  335. load = {
  336. "user": "foo",
  337. "fun": "test.arg",
  338. "tgt": "test_minion",
  339. "arg": "bar",
  340. "kwargs": {"token": token},
  341. }
  342. mock_token = {"token": token, "eauth": "foo", "name": "test"}
  343. mock_ret = {
  344. "error": {
  345. "name": "AuthorizationError",
  346. "message": "Authorization error occurred.",
  347. }
  348. }
  349. with patch(
  350. "salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
  351. ), patch(
  352. "salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
  353. ), patch(
  354. "salt.auth.LoadAuth.authenticate_token", MagicMock(return_value=mock_token)
  355. ), patch(
  356. "salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])
  357. ):
  358. self.assertEqual(mock_ret, self.clear_funcs.publish(load))
  359. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  360. def test_publish_eauth_not_authenticated(self):
  361. """
  362. Asserts that an AuthenticationError is returned when the user can't authenticate.
  363. """
  364. load = {
  365. "user": "test",
  366. "fun": "test.arg",
  367. "tgt": "test_minion",
  368. "kwargs": {"eauth": "foo"},
  369. }
  370. mock_ret = {
  371. "error": {
  372. "name": "AuthenticationError",
  373. "message": "Authentication error occurred.",
  374. }
  375. }
  376. with patch(
  377. "salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
  378. ), patch(
  379. "salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
  380. ):
  381. self.assertEqual(mock_ret, self.clear_funcs.publish(load))
  382. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  383. def test_publish_eauth_authorization_error(self):
  384. """
  385. Asserts that an AuthorizationError is returned when the user authenticates, but is not
  386. authorized.
  387. """
  388. load = {
  389. "user": "test",
  390. "fun": "test.arg",
  391. "tgt": "test_minion",
  392. "kwargs": {"eauth": "foo"},
  393. "arg": "bar",
  394. }
  395. mock_ret = {
  396. "error": {
  397. "name": "AuthorizationError",
  398. "message": "Authorization error occurred.",
  399. }
  400. }
  401. with patch(
  402. "salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
  403. ), patch(
  404. "salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
  405. ), patch(
  406. "salt.auth.LoadAuth.authenticate_eauth", MagicMock(return_value=True)
  407. ), patch(
  408. "salt.auth.LoadAuth.get_auth_list", MagicMock(return_value=[])
  409. ):
  410. self.assertEqual(mock_ret, self.clear_funcs.publish(load))
  411. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  412. def test_publish_user_not_authenticated(self):
  413. """
  414. Asserts that an AuthenticationError is returned when the user can't authenticate.
  415. """
  416. load = {"user": "test", "fun": "test.arg", "tgt": "test_minion"}
  417. mock_ret = {
  418. "error": {
  419. "name": "AuthenticationError",
  420. "message": "Authentication error occurred.",
  421. }
  422. }
  423. with patch(
  424. "salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
  425. ), patch(
  426. "salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
  427. ):
  428. self.assertEqual(mock_ret, self.clear_funcs.publish(load))
  429. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  430. def test_publish_user_authenticated_missing_auth_list(self):
  431. """
  432. Asserts that an AuthenticationError is returned when the user has an effective user id and is
  433. authenticated, but the auth_list is empty.
  434. """
  435. load = {
  436. "user": "test",
  437. "fun": "test.arg",
  438. "tgt": "test_minion",
  439. "kwargs": {"user": "test"},
  440. "arg": "foo",
  441. }
  442. mock_ret = {
  443. "error": {
  444. "name": "AuthenticationError",
  445. "message": "Authentication error occurred.",
  446. }
  447. }
  448. with patch(
  449. "salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
  450. ), patch(
  451. "salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
  452. ), patch(
  453. "salt.auth.LoadAuth.authenticate_key",
  454. MagicMock(return_value="fake-user-key"),
  455. ), patch(
  456. "salt.utils.master.get_values_of_matching_keys", MagicMock(return_value=[])
  457. ):
  458. self.assertEqual(mock_ret, self.clear_funcs.publish(load))
  459. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  460. def test_publish_user_authorization_error(self):
  461. """
  462. Asserts that an AuthorizationError is returned when the user authenticates, but is not
  463. authorized.
  464. """
  465. load = {
  466. "user": "test",
  467. "fun": "test.arg",
  468. "tgt": "test_minion",
  469. "kwargs": {"user": "test"},
  470. "arg": "foo",
  471. }
  472. mock_ret = {
  473. "error": {
  474. "name": "AuthorizationError",
  475. "message": "Authorization error occurred.",
  476. }
  477. }
  478. with patch(
  479. "salt.acl.PublisherACL.user_is_blacklisted", MagicMock(return_value=False)
  480. ), patch(
  481. "salt.acl.PublisherACL.cmd_is_blacklisted", MagicMock(return_value=False)
  482. ), patch(
  483. "salt.auth.LoadAuth.authenticate_key",
  484. MagicMock(return_value="fake-user-key"),
  485. ), patch(
  486. "salt.utils.master.get_values_of_matching_keys",
  487. MagicMock(return_value=["test"]),
  488. ), patch(
  489. "salt.utils.minions.CkMinions.auth_check", MagicMock(return_value=False)
  490. ):
  491. self.assertEqual(mock_ret, self.clear_funcs.publish(load))