test_app.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. # coding: utf-8
  2. # Import python libs
  3. from __future__ import absolute_import
  4. import os
  5. # Import salt libs
  6. import salt.utils.json
  7. import salt.utils.stringutils
  8. # Import test support libs
  9. import tests.support.cherrypy_testclasses as cptc
  10. # Import 3rd-party libs
  11. from salt.ext.six.moves.urllib.parse import ( # pylint: disable=no-name-in-module,import-error
  12. urlencode,
  13. )
  14. from tests.support.helpers import flaky
  15. from tests.support.unit import skipIf
  16. class TestAuth(cptc.BaseRestCherryPyTest):
  17. def test_get_root_noauth(self):
  18. """
  19. GET requests to the root URL should not require auth
  20. """
  21. request, response = self.request("/")
  22. self.assertEqual(response.status, "200 OK")
  23. def test_post_root_auth(self):
  24. """
  25. POST requests to the root URL redirect to login
  26. """
  27. request, response = self.request("/", method="POST", data={})
  28. self.assertEqual(response.status, "401 Unauthorized")
  29. def test_login_noauth(self):
  30. """
  31. GET requests to the login URL should not require auth
  32. """
  33. request, response = self.request("/login")
  34. self.assertEqual(response.status, "200 OK")
  35. def test_webhook_auth(self):
  36. """
  37. Requests to the webhook URL require auth by default
  38. """
  39. request, response = self.request("/hook", method="POST", data={})
  40. self.assertEqual(response.status, "401 Unauthorized")
  41. class TestLogin(cptc.BaseRestCherryPyTest):
  42. auth_creds = (("username", "saltdev"), ("password", "saltdev"), ("eauth", "auto"))
  43. def test_good_login(self):
  44. """
  45. Test logging in
  46. """
  47. body = urlencode(self.auth_creds)
  48. request, response = self.request(
  49. "/login",
  50. method="POST",
  51. body=body,
  52. headers={"content-type": "application/x-www-form-urlencoded"},
  53. )
  54. self.assertEqual(response.status, "200 OK")
  55. return response
  56. def test_bad_login(self):
  57. """
  58. Test logging in
  59. """
  60. body = urlencode({"totally": "invalid_creds"})
  61. request, response = self.request(
  62. "/login",
  63. method="POST",
  64. body=body,
  65. headers={"content-type": "application/x-www-form-urlencoded"},
  66. )
  67. self.assertEqual(response.status, "401 Unauthorized")
  68. def test_logout(self):
  69. ret = self.test_good_login()
  70. token = ret.headers["X-Auth-Token"]
  71. body = urlencode({})
  72. request, response = self.request(
  73. "/logout",
  74. method="POST",
  75. body=body,
  76. headers={
  77. "content-type": "application/x-www-form-urlencoded",
  78. "X-Auth-Token": token,
  79. },
  80. )
  81. self.assertEqual(response.status, "200 OK")
  82. class TestRun(cptc.BaseRestCherryPyTest):
  83. auth_creds = (
  84. ("username", "saltdev_auto"),
  85. ("password", "saltdev"),
  86. ("eauth", "auto"),
  87. )
  88. low = (
  89. ("client", "local"),
  90. ("tgt", "*"),
  91. ("fun", "test.ping"),
  92. )
  93. @skipIf(True, "SLOWTEST skip")
  94. def test_run_good_login(self):
  95. """
  96. Test the run URL with good auth credentials
  97. """
  98. cmd = dict(self.low, **dict(self.auth_creds))
  99. body = urlencode(cmd)
  100. request, response = self.request(
  101. "/run",
  102. method="POST",
  103. body=body,
  104. headers={"content-type": "application/x-www-form-urlencoded"},
  105. )
  106. self.assertEqual(response.status, "200 OK")
  107. def test_run_bad_login(self):
  108. """
  109. Test the run URL with bad auth credentials
  110. """
  111. cmd = dict(self.low, **{"totally": "invalid_creds"})
  112. body = urlencode(cmd)
  113. request, response = self.request(
  114. "/run",
  115. method="POST",
  116. body=body,
  117. headers={"content-type": "application/x-www-form-urlencoded"},
  118. )
  119. self.assertEqual(response.status, "401 Unauthorized")
  120. def test_run_empty_token(self):
  121. """
  122. Test the run URL with empty token
  123. """
  124. cmd = dict(self.low, **{"token": ""})
  125. body = urlencode(cmd)
  126. request, response = self.request(
  127. "/run",
  128. method="POST",
  129. body=body,
  130. headers={"content-type": "application/x-www-form-urlencoded"},
  131. )
  132. assert response.status == "401 Unauthorized"
  133. def test_run_empty_token_upercase(self):
  134. """
  135. Test the run URL with empty token with upercase characters
  136. """
  137. cmd = dict(self.low, **{"ToKen": ""})
  138. body = urlencode(cmd)
  139. request, response = self.request(
  140. "/run",
  141. method="POST",
  142. body=body,
  143. headers={"content-type": "application/x-www-form-urlencoded"},
  144. )
  145. assert response.status == "401 Unauthorized"
  146. def test_run_wrong_token(self):
  147. """
  148. Test the run URL with incorrect token
  149. """
  150. cmd = dict(self.low, **{"token": "bad"})
  151. body = urlencode(cmd)
  152. request, response = self.request(
  153. "/run",
  154. method="POST",
  155. body=body,
  156. headers={"content-type": "application/x-www-form-urlencoded"},
  157. )
  158. assert response.status == "401 Unauthorized"
  159. def test_run_pathname_token(self):
  160. """
  161. Test the run URL with path that exists in token
  162. """
  163. cmd = dict(self.low, **{"token": os.path.join("etc", "passwd")})
  164. body = urlencode(cmd)
  165. request, response = self.request(
  166. "/run",
  167. method="POST",
  168. body=body,
  169. headers={"content-type": "application/x-www-form-urlencoded"},
  170. )
  171. assert response.status == "401 Unauthorized"
  172. def test_run_pathname_not_exists_token(self):
  173. """
  174. Test the run URL with path that does not exist in token
  175. """
  176. cmd = dict(self.low, **{"token": os.path.join("tmp", "doesnotexist")})
  177. body = urlencode(cmd)
  178. request, response = self.request(
  179. "/run",
  180. method="POST",
  181. body=body,
  182. headers={"content-type": "application/x-www-form-urlencoded"},
  183. )
  184. assert response.status == "401 Unauthorized"
  185. @skipIf(True, "SLOWTEST skip")
  186. def test_run_extra_parameters(self):
  187. """
  188. Test the run URL with good auth credentials
  189. """
  190. cmd = dict(self.low, **dict(self.auth_creds))
  191. cmd["id_"] = "someminionname"
  192. body = urlencode(cmd)
  193. request, response = self.request(
  194. "/run",
  195. method="POST",
  196. body=body,
  197. headers={"content-type": "application/x-www-form-urlencoded"},
  198. )
  199. self.assertEqual(response.status, "200 OK")
  200. class TestWebhookDisableAuth(cptc.BaseRestCherryPyTest):
  201. def __get_opts__(self):
  202. return {
  203. "rest_cherrypy": {
  204. "port": 8000,
  205. "debug": True,
  206. "webhook_disable_auth": True,
  207. },
  208. }
  209. def test_webhook_noauth(self):
  210. """
  211. Auth can be disabled for requests to the webhook URL
  212. """
  213. body = urlencode({"foo": "Foo!"})
  214. request, response = self.request(
  215. "/hook",
  216. method="POST",
  217. body=body,
  218. headers={"content-type": "application/x-www-form-urlencoded"},
  219. )
  220. self.assertEqual(response.status, "200 OK")
  221. class TestArgKwarg(cptc.BaseRestCherryPyTest):
  222. auth_creds = (("username", "saltdev"), ("password", "saltdev"), ("eauth", "auto"))
  223. low = (
  224. ("client", "runner"),
  225. ("fun", "test.arg"),
  226. # use singular form for arg and kwarg
  227. ("arg", [1234]),
  228. ("kwarg", {"ext_source": "redis"}),
  229. )
  230. def _token(self):
  231. """
  232. Return the token
  233. """
  234. body = urlencode(self.auth_creds)
  235. request, response = self.request(
  236. "/login",
  237. method="POST",
  238. body=body,
  239. headers={"content-type": "application/x-www-form-urlencoded"},
  240. )
  241. return response.headers["X-Auth-Token"]
  242. @skipIf(True, "SLOWTEST skip")
  243. def test_accepts_arg_kwarg_keys(self):
  244. """
  245. Ensure that (singular) arg and kwarg keys (for passing parameters)
  246. are supported by runners.
  247. """
  248. cmd = dict(self.low)
  249. body = salt.utils.json.dumps(cmd)
  250. request, response = self.request(
  251. "/",
  252. method="POST",
  253. body=body,
  254. headers={
  255. "content-type": "application/json",
  256. "X-Auth-Token": self._token(),
  257. "Accept": "application/json",
  258. },
  259. )
  260. resp = salt.utils.json.loads(salt.utils.stringutils.to_str(response.body[0]))
  261. self.assertEqual(resp["return"][0]["args"], [1234])
  262. self.assertEqual(resp["return"][0]["kwargs"], {"ext_source": "redis"})
  263. class TestJobs(cptc.BaseRestCherryPyTest):
  264. auth_creds = (
  265. ("username", "saltdev_auto"),
  266. ("password", "saltdev"),
  267. ("eauth", "auto"),
  268. )
  269. low = (
  270. ("client", "local"),
  271. ("tgt", "*"),
  272. ("fun", "test.ping"),
  273. )
  274. def _token(self):
  275. """
  276. Return the token
  277. """
  278. body = urlencode(self.auth_creds)
  279. request, response = self.request(
  280. "/login",
  281. method="POST",
  282. body=body,
  283. headers={"content-type": "application/x-www-form-urlencoded"},
  284. )
  285. return response.headers["X-Auth-Token"]
  286. def _add_job(self):
  287. """
  288. Helper function to add a job to the job cache
  289. """
  290. cmd = dict(self.low, **dict(self.auth_creds))
  291. body = urlencode(cmd)
  292. request, response = self.request(
  293. "/run",
  294. method="POST",
  295. body=body,
  296. headers={"content-type": "application/x-www-form-urlencoded"},
  297. )
  298. self.assertEqual(response.status, "200 OK")
  299. @flaky
  300. @skipIf(True, "SLOWTEST skip")
  301. def test_all_jobs(self):
  302. """
  303. test query to /jobs returns job data
  304. """
  305. self._add_job()
  306. request, response = self.request(
  307. "/jobs",
  308. method="GET",
  309. headers={"Accept": "application/json", "X-Auth-Token": self._token()},
  310. )
  311. resp = salt.utils.json.loads(salt.utils.stringutils.to_str(response.body[0]))
  312. self.assertIn("test.ping", str(resp["return"]))
  313. self.assertEqual(response.status, "200 OK")