test_mac_keychain.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. # -*- coding: utf-8 -*-
  2. # Import Python libs
  3. from __future__ import absolute_import, unicode_literals, print_function
  4. # Import Salt Libs
  5. import salt.states.mac_keychain as keychain
  6. # Import Salt Testing Libs
  7. from tests.support.mixins import LoaderModuleMockMixin
  8. from tests.support.unit import TestCase
  9. from tests.support.mock import (
  10. MagicMock,
  11. patch,
  12. call
  13. )
  14. class KeychainTestCase(TestCase, LoaderModuleMockMixin):
  15. def setup_loader_modules(self):
  16. return {keychain: {}}
  17. def test_install_cert(self):
  18. '''
  19. Test installing a certificate into the macOS keychain
  20. '''
  21. expected = {
  22. 'changes': {'installed': 'Friendly Name'},
  23. 'comment': '',
  24. 'name': '/path/to/cert.p12',
  25. 'result': True
  26. }
  27. list_mock = MagicMock(return_value=['Cert1'])
  28. friendly_mock = MagicMock(return_value='Friendly Name')
  29. install_mock = MagicMock(return_value='1 identity imported.')
  30. with patch.dict(keychain.__salt__, {'keychain.list_certs': list_mock,
  31. 'keychain.get_friendly_name': friendly_mock,
  32. 'keychain.install': install_mock}):
  33. out = keychain.installed('/path/to/cert.p12', 'passw0rd')
  34. list_mock.assert_called_once_with('/Library/Keychains/System.keychain')
  35. friendly_mock.assert_called_once_with('/path/to/cert.p12', 'passw0rd')
  36. install_mock.assert_called_once_with('/path/to/cert.p12', 'passw0rd', '/Library/Keychains/System.keychain')
  37. self.assertEqual(out, expected)
  38. def test_installed_cert(self):
  39. '''
  40. Test installing a certificate into the macOS keychain when it's
  41. already installed
  42. '''
  43. expected = {
  44. 'changes': {},
  45. 'comment': 'Friendly Name already installed.',
  46. 'name': '/path/to/cert.p12',
  47. 'result': True
  48. }
  49. list_mock = MagicMock(return_value=['Friendly Name'])
  50. friendly_mock = MagicMock(return_value='Friendly Name')
  51. install_mock = MagicMock(return_value='1 identity imported.')
  52. hash_mock = MagicMock(return_value='ABCD')
  53. with patch.dict(keychain.__salt__, {'keychain.list_certs': list_mock,
  54. 'keychain.get_friendly_name': friendly_mock,
  55. 'keychain.install': install_mock,
  56. 'keychain.get_hash': hash_mock}):
  57. out = keychain.installed('/path/to/cert.p12', 'passw0rd')
  58. list_mock.assert_called_once_with('/Library/Keychains/System.keychain')
  59. friendly_mock.assert_called_once_with('/path/to/cert.p12', 'passw0rd')
  60. assert not install_mock.called
  61. self.assertEqual(out, expected)
  62. def test_uninstall_cert(self):
  63. '''
  64. Test uninstalling a certificate into the macOS keychain when it's
  65. already installed
  66. '''
  67. expected = {
  68. 'changes': {'uninstalled': 'Friendly Name'},
  69. 'comment': '',
  70. 'name': '/path/to/cert.p12',
  71. 'result': True
  72. }
  73. list_mock = MagicMock(return_value=['Friendly Name'])
  74. friendly_mock = MagicMock(return_value='Friendly Name')
  75. uninstall_mock = MagicMock(return_value='1 identity imported.')
  76. with patch.dict(keychain.__salt__, {'keychain.list_certs': list_mock,
  77. 'keychain.get_friendly_name': friendly_mock,
  78. 'keychain.uninstall': uninstall_mock}):
  79. out = keychain.uninstalled('/path/to/cert.p12', 'passw0rd')
  80. list_mock.assert_called_once_with('/Library/Keychains/System.keychain')
  81. friendly_mock.assert_called_once_with('/path/to/cert.p12', 'passw0rd')
  82. uninstall_mock.assert_called_once_with('Friendly Name', '/Library/Keychains/System.keychain', None)
  83. self.assertEqual(out, expected)
  84. def test_uninstalled_cert(self):
  85. '''
  86. Test uninstalling a certificate into the macOS keychain when it's
  87. not installed
  88. '''
  89. expected = {
  90. 'changes': {},
  91. 'comment': 'Friendly Name already uninstalled.',
  92. 'name': '/path/to/cert.p12',
  93. 'result': True
  94. }
  95. list_mock = MagicMock(return_value=['Cert2'])
  96. friendly_mock = MagicMock(return_value='Friendly Name')
  97. uninstall_mock = MagicMock(return_value='1 identity imported.')
  98. with patch.dict(keychain.__salt__, {'keychain.list_certs': list_mock,
  99. 'keychain.get_friendly_name': friendly_mock,
  100. 'keychain.uninstall': uninstall_mock}):
  101. out = keychain.uninstalled('/path/to/cert.p12', 'passw0rd')
  102. list_mock.assert_called_once_with('/Library/Keychains/System.keychain')
  103. friendly_mock.assert_called_once_with('/path/to/cert.p12', 'passw0rd')
  104. assert not uninstall_mock.called
  105. self.assertEqual(out, expected)
  106. def test_default_keychain(self):
  107. '''
  108. Test setting the default keychain
  109. '''
  110. with patch('os.path.exists') as exists_mock:
  111. expected = {
  112. 'changes': {'default': '/path/to/chain.keychain'},
  113. 'comment': '',
  114. 'name': '/path/to/chain.keychain',
  115. 'result': True
  116. }
  117. exists_mock.return_value = True
  118. get_default_mock = MagicMock(return_value='/path/to/other.keychain')
  119. set_mock = MagicMock(return_value='')
  120. with patch.dict(keychain.__salt__, {'keychain.get_default_keychain': get_default_mock,
  121. 'keychain.set_default_keychain': set_mock}):
  122. out = keychain.default_keychain('/path/to/chain.keychain', 'system', 'frank')
  123. get_default_mock.assert_called_once_with('frank', 'system')
  124. set_mock.assert_called_once_with('/path/to/chain.keychain', 'system', 'frank')
  125. self.assertEqual(out, expected)
  126. def test_default_keychain_set_already(self):
  127. '''
  128. Test setting the default keychain when it's already set
  129. '''
  130. with patch('os.path.exists') as exists_mock:
  131. expected = {
  132. 'changes': {},
  133. 'comment': '/path/to/chain.keychain was already the default keychain.',
  134. 'name': '/path/to/chain.keychain',
  135. 'result': True
  136. }
  137. exists_mock.return_value = True
  138. get_default_mock = MagicMock(return_value='/path/to/chain.keychain')
  139. set_mock = MagicMock(return_value='')
  140. with patch.dict(keychain.__salt__, {'keychain.get_default_keychain': get_default_mock,
  141. 'keychain.set_default_keychain': set_mock}):
  142. out = keychain.default_keychain('/path/to/chain.keychain', 'system', 'frank')
  143. get_default_mock.assert_called_once_with('frank', 'system')
  144. assert not set_mock.called
  145. self.assertEqual(out, expected)
  146. def test_default_keychain_missing(self):
  147. '''
  148. Test setting the default keychain when the keychain is missing
  149. '''
  150. with patch('os.path.exists') as exists_mock:
  151. expected = {
  152. 'changes': {},
  153. 'comment': 'Keychain not found at /path/to/cert.p12',
  154. 'name': '/path/to/cert.p12',
  155. 'result': False
  156. }
  157. exists_mock.return_value = False
  158. out = keychain.default_keychain('/path/to/cert.p12', 'system', 'frank')
  159. self.assertEqual(out, expected)
  160. def test_install_cert_salt_fileserver(self):
  161. '''
  162. Test installing a certificate into the macOS keychain from the salt
  163. fileserver
  164. '''
  165. expected = {
  166. 'changes': {'installed': 'Friendly Name'},
  167. 'comment': '',
  168. 'name': 'salt://path/to/cert.p12',
  169. 'result': True
  170. }
  171. list_mock = MagicMock(return_value=['Cert1'])
  172. friendly_mock = MagicMock(return_value='Friendly Name')
  173. install_mock = MagicMock(return_value='1 identity imported.')
  174. cp_cache_mock = MagicMock(return_value='/tmp/path/to/cert.p12')
  175. with patch.dict(keychain.__salt__, {'keychain.list_certs': list_mock,
  176. 'keychain.get_friendly_name': friendly_mock,
  177. 'keychain.install': install_mock,
  178. 'cp.cache_file': cp_cache_mock}):
  179. out = keychain.installed('salt://path/to/cert.p12', 'passw0rd')
  180. list_mock.assert_called_once_with('/Library/Keychains/System.keychain')
  181. friendly_mock.assert_called_once_with('/tmp/path/to/cert.p12', 'passw0rd')
  182. install_mock.assert_called_once_with('/tmp/path/to/cert.p12', 'passw0rd', '/Library/Keychains/System.keychain')
  183. self.assertEqual(out, expected)
  184. def test_installed_cert_hash_different(self):
  185. '''
  186. Test installing a certificate into the macOS keychain when it's
  187. already installed but the certificate has changed
  188. '''
  189. expected = {
  190. 'changes': {'installed': 'Friendly Name', 'uninstalled': 'Friendly Name'},
  191. 'comment': 'Found a certificate with the same name but different hash, removing it.\n',
  192. 'name': '/path/to/cert.p12',
  193. 'result': True
  194. }
  195. list_mock = MagicMock(side_effect=[['Friendly Name'], []])
  196. friendly_mock = MagicMock(return_value='Friendly Name')
  197. install_mock = MagicMock(return_value='1 identity imported.')
  198. uninstall_mock = MagicMock(return_value='removed.')
  199. hash_mock = MagicMock(side_effect=['ABCD', 'XYZ'])
  200. with patch.dict(keychain.__salt__, {'keychain.list_certs': list_mock,
  201. 'keychain.get_friendly_name': friendly_mock,
  202. 'keychain.install': install_mock,
  203. 'keychain.uninstall': uninstall_mock,
  204. 'keychain.get_hash': hash_mock}):
  205. out = keychain.installed('/path/to/cert.p12', 'passw0rd')
  206. list_mock.assert_has_calls(calls=[call('/Library/Keychains/System.keychain'),
  207. call('/Library/Keychains/System.keychain')])
  208. friendly_mock.assert_called_once_with('/path/to/cert.p12', 'passw0rd')
  209. install_mock.assert_called_once_with('/path/to/cert.p12', 'passw0rd', '/Library/Keychains/System.keychain')
  210. uninstall_mock.assert_called_once_with('Friendly Name', '/Library/Keychains/System.keychain',
  211. keychain_password=None)
  212. self.assertEqual(out, expected)