test_app.py 10 KB

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