1
0

test_url.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. # -*- coding: utf-8 -*-
  2. # Import python libs
  3. from __future__ import absolute_import, print_function, unicode_literals
  4. # Import Salt Libs
  5. import salt.utils.platform
  6. import salt.utils.url
  7. # Import Salt Testing Libs
  8. from tests.support.unit import TestCase
  9. from tests.support.mock import (
  10. MagicMock,
  11. patch,
  12. )
  13. class UrlTestCase(TestCase):
  14. '''
  15. TestCase for salt.utils.url module
  16. '''
  17. # parse tests
  18. def test_parse_path(self):
  19. '''
  20. Test parsing an ordinary path
  21. '''
  22. path = 'interesting?/path&.conf:and other things'
  23. self.assertEqual(salt.utils.url.parse(path), (path, None))
  24. def test_parse_salt_url(self):
  25. '''
  26. Test parsing a 'salt://' URL
  27. '''
  28. path = '?funny/path with {interesting|chars}'
  29. url = 'salt://' + path
  30. if salt.utils.platform.is_windows():
  31. path = '_funny/path with {interesting_chars}'
  32. self.assertEqual(salt.utils.url.parse(url), (path, None))
  33. def test_parse_salt_saltenv(self):
  34. '''
  35. Test parsing a 'salt://' URL with a '?saltenv=' query
  36. '''
  37. saltenv = 'ambience'
  38. path = '?funny/path&with {interesting|chars}'
  39. url = 'salt://' + path + '?saltenv=' + saltenv
  40. if salt.utils.platform.is_windows():
  41. path = '_funny/path&with {interesting_chars}'
  42. self.assertEqual(salt.utils.url.parse(url), (path, saltenv))
  43. # create tests
  44. def test_create_url(self):
  45. '''
  46. Test creating a 'salt://' URL
  47. '''
  48. path = '? interesting/&path.filetype'
  49. url = 'salt://' + path
  50. if salt.utils.platform.is_windows():
  51. url = 'salt://_ interesting/&path.filetype'
  52. self.assertEqual(salt.utils.url.create(path), url)
  53. def test_create_url_saltenv(self):
  54. '''
  55. Test creating a 'salt://' URL with a saltenv
  56. '''
  57. saltenv = 'raumklang'
  58. path = '? interesting/&path.filetype'
  59. if salt.utils.platform.is_windows():
  60. path = '_ interesting/&path.filetype'
  61. url = 'salt://' + path + '?saltenv=' + saltenv
  62. self.assertEqual(salt.utils.url.create(path, saltenv), url)
  63. # is_escaped tests
  64. def test_is_escaped_windows(self):
  65. '''
  66. Test not testing a 'salt://' URL on windows
  67. '''
  68. url = 'salt://dir/file.ini'
  69. with patch('salt.utils.platform.is_windows', MagicMock(return_value=True)):
  70. self.assertFalse(salt.utils.url.is_escaped(url))
  71. def test_is_escaped_escaped_path(self):
  72. '''
  73. Test testing an escaped path
  74. '''
  75. path = '|dir/file.conf?saltenv=basic'
  76. self.assertTrue(salt.utils.url.is_escaped(path))
  77. def test_is_escaped_unescaped_path(self):
  78. '''
  79. Test testing an unescaped path
  80. '''
  81. path = 'dir/file.conf'
  82. self.assertFalse(salt.utils.url.is_escaped(path))
  83. def test_is_escaped_escaped_url(self):
  84. '''
  85. Test testing an escaped 'salt://' URL
  86. '''
  87. url = 'salt://|dir/file.conf?saltenv=basic'
  88. self.assertTrue(salt.utils.url.is_escaped(url))
  89. def test_is_escaped_unescaped_url(self):
  90. '''
  91. Test testing an unescaped 'salt://' URL
  92. '''
  93. url = 'salt://dir/file.conf'
  94. self.assertFalse(salt.utils.url.is_escaped(url))
  95. def test_is_escaped_generic_url(self):
  96. '''
  97. Test testing an unescaped 'salt://' URL
  98. '''
  99. url = 'https://gentoo.org/'
  100. self.assertFalse(salt.utils.url.is_escaped(url))
  101. # escape tests
  102. def test_escape_windows(self):
  103. '''
  104. Test not escaping a 'salt://' URL on windows
  105. '''
  106. url = 'salt://dir/file.ini'
  107. with patch('salt.utils.platform.is_windows', MagicMock(return_value=True)):
  108. self.assertEqual(salt.utils.url.escape(url), url)
  109. def test_escape_escaped_path(self):
  110. '''
  111. Test escaping an escaped path
  112. '''
  113. resource = '|dir/file.conf?saltenv=basic'
  114. self.assertEqual(salt.utils.url.escape(resource), resource)
  115. def test_escape_unescaped_path(self):
  116. '''
  117. Test escaping an unescaped path
  118. '''
  119. path = 'dir/file.conf'
  120. escaped_path = '|' + path
  121. if salt.utils.platform.is_windows():
  122. escaped_path = path
  123. self.assertEqual(salt.utils.url.escape(path), escaped_path)
  124. def test_escape_escaped_url(self):
  125. '''
  126. Test testing an escaped 'salt://' URL
  127. '''
  128. url = 'salt://|dir/file.conf?saltenv=basic'
  129. self.assertEqual(salt.utils.url.escape(url), url)
  130. def test_escape_unescaped_url(self):
  131. '''
  132. Test testing an unescaped 'salt://' URL
  133. '''
  134. path = 'dir/file.conf'
  135. url = 'salt://' + path
  136. escaped_url = 'salt://|' + path
  137. if salt.utils.platform.is_windows():
  138. escaped_url = url
  139. self.assertEqual(salt.utils.url.escape(url), escaped_url)
  140. def test_escape_generic_url(self):
  141. '''
  142. Test testing an unescaped 'salt://' URL
  143. '''
  144. url = 'https://gentoo.org/'
  145. self.assertEqual(salt.utils.url.escape(url), url)
  146. # unescape tests
  147. def test_unescape_windows(self):
  148. '''
  149. Test not escaping a 'salt://' URL on windows
  150. '''
  151. url = 'salt://dir/file.ini'
  152. with patch('salt.utils.platform.is_windows', MagicMock(return_value=True)):
  153. self.assertEqual(salt.utils.url.unescape(url), url)
  154. def test_unescape_escaped_path(self):
  155. '''
  156. Test escaping an escaped path
  157. '''
  158. resource = 'dir/file.conf?saltenv=basic'
  159. escaped_path = '|' + resource
  160. self.assertEqual(salt.utils.url.unescape(escaped_path), resource)
  161. def test_unescape_unescaped_path(self):
  162. '''
  163. Test escaping an unescaped path
  164. '''
  165. path = 'dir/file.conf'
  166. self.assertEqual(salt.utils.url.unescape(path), path)
  167. def test_unescape_escaped_url(self):
  168. '''
  169. Test testing an escaped 'salt://' URL
  170. '''
  171. resource = 'dir/file.conf?saltenv=basic'
  172. url = 'salt://' + resource
  173. escaped_url = 'salt://|' + resource
  174. self.assertEqual(salt.utils.url.unescape(escaped_url), url)
  175. def test_unescape_unescaped_url(self):
  176. '''
  177. Test testing an unescaped 'salt://' URL
  178. '''
  179. url = 'salt://dir/file.conf'
  180. self.assertEqual(salt.utils.url.unescape(url), url)
  181. def test_unescape_generic_url(self):
  182. '''
  183. Test testing an unescaped 'salt://' URL
  184. '''
  185. url = 'https://gentoo.org/'
  186. self.assertEqual(salt.utils.url.unescape(url), url)
  187. # add_env tests
  188. def test_add_env_not_salt(self):
  189. '''
  190. Test not adding a saltenv to a non 'salt://' URL
  191. '''
  192. saltenv = 'higgs'
  193. url = 'https://pdg.lbl.gov/'
  194. self.assertEqual(salt.utils.url.add_env(url, saltenv), url)
  195. def test_add_env(self):
  196. '''
  197. Test adding a saltenv to a 'salt://' URL
  198. '''
  199. saltenv = 'erstwhile'
  200. url = 'salt://salted/file.conf'
  201. url_env = url + '?saltenv=' + saltenv
  202. self.assertEqual(salt.utils.url.add_env(url, saltenv), url_env)
  203. # split_env tests
  204. def test_split_env_non_salt(self):
  205. '''
  206. Test not splitting a saltenv from a non 'salt://' URL
  207. '''
  208. saltenv = 'gravitodynamics'
  209. url = 'https://arxiv.org/find/all/?' + saltenv
  210. self.assertEqual(salt.utils.url.split_env(url), (url, None))
  211. def test_split_env(self):
  212. '''
  213. Test splitting a 'salt://' URL
  214. '''
  215. saltenv = 'elsewhere'
  216. url = 'salt://salted/file.conf'
  217. url_env = url + '?saltenv=' + saltenv
  218. self.assertEqual(salt.utils.url.split_env(url_env), (url, saltenv))
  219. # validate tests
  220. def test_validate_valid(self):
  221. '''
  222. Test URL valid validation
  223. '''
  224. url = 'salt://config/file.name?saltenv=vapid'
  225. protos = ['salt', 'pepper', 'cinnamon', 'melange']
  226. self.assertTrue(salt.utils.url.validate(url, protos))
  227. def test_validate_invalid(self):
  228. '''
  229. Test URL invalid validation
  230. '''
  231. url = 'cumin://config/file.name?saltenv=vapid'
  232. protos = ['salt', 'pepper', 'cinnamon', 'melange']
  233. self.assertFalse(salt.utils.url.validate(url, protos))
  234. # strip tests
  235. def test_strip_url_with_scheme(self):
  236. '''
  237. Test stripping of URL scheme
  238. '''
  239. scheme = 'git+salt+rsync+AYB://'
  240. resource = 'all/the/things.stuff;parameter?query=I guess'
  241. url = scheme + resource
  242. self.assertEqual(salt.utils.url.strip_proto(url), resource)
  243. def test_strip_url_without_scheme(self):
  244. '''
  245. Test stripping of a URL without a scheme
  246. '''
  247. resource = 'all/the/things.stuff;parameter?query=I guess'
  248. self.assertEqual(salt.utils.url.strip_proto(resource), resource)
  249. def test_http_basic_auth(self):
  250. '''
  251. Tests that adding basic auth to a URL works as expected
  252. '''
  253. # ((user, password), expected) tuples
  254. test_inputs = (
  255. ((None, None), 'http://example.com'),
  256. (('user', None), 'http://user@example.com'),
  257. (('user', 'pass'), 'http://user:pass@example.com'),
  258. )
  259. for (user, password), expected in test_inputs:
  260. kwargs = {
  261. 'url': 'http://example.com',
  262. 'user': user,
  263. 'password': password,
  264. }
  265. # Test http
  266. result = salt.utils.url.add_http_basic_auth(**kwargs)
  267. self.assertEqual(result, expected)
  268. # Test https
  269. kwargs['url'] = kwargs['url'].replace('http://', 'https://', 1)
  270. expected = expected.replace('http://', 'https://', 1)
  271. result = salt.utils.url.add_http_basic_auth(**kwargs)
  272. self.assertEqual(result, expected)
  273. def test_http_basic_auth_https_only(self):
  274. '''
  275. Tests that passing a non-https URL with https_only=True will raise a
  276. ValueError.
  277. '''
  278. kwargs = {
  279. 'url': 'http://example.com',
  280. 'user': 'foo',
  281. 'password': 'bar',
  282. 'https_only': True,
  283. }
  284. self.assertRaises(
  285. ValueError,
  286. salt.utils.url.add_http_basic_auth,
  287. **kwargs
  288. )
  289. def test_redact_http_basic_auth(self):
  290. sensitive_outputs = (
  291. 'https://deadbeaf@example.com',
  292. 'https://user:pw@example.com',
  293. )
  294. sanitized = 'https://<redacted>@example.com'
  295. for sensitive_output in sensitive_outputs:
  296. result = salt.utils.url.redact_http_basic_auth(sensitive_output)
  297. self.assertEqual(result, sanitized)
  298. def test_redact_non_auth_output(self):
  299. non_auth_output = 'This is just normal output'
  300. self.assertEqual(
  301. non_auth_output,
  302. salt.utils.url.redact_http_basic_auth(non_auth_output)
  303. )