test_btmp.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. # coding: utf-8
  2. # Python libs
  3. from __future__ import absolute_import
  4. import datetime
  5. import logging
  6. # Salt testing libs
  7. from tests.support.unit import skipIf, TestCase
  8. from tests.support.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock, mock_open
  9. from tests.support.mixins import LoaderModuleMockMixin
  10. # Salt libs
  11. import salt.beacons.btmp as btmp
  12. from salt.ext import six
  13. # pylint: disable=import-error
  14. try:
  15. import dateutil.parser as dateutil_parser # pylint: disable=unused-import
  16. _TIME_SUPPORTED = True
  17. except ImportError:
  18. _TIME_SUPPORTED = False
  19. raw = b'\x06\x00\x00\x00Nt\x00\x00ssh:notty\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00garet\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00::1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdd\xc7\xc2Y\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
  20. pack = (6, 29774, b'ssh:notty\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x00\x00\x00\x00', b'garet\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'::1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 0, 0, 0, 1505937373, 0, 0, 0, 0, 16777216)
  21. log = logging.getLogger(__name__)
  22. @skipIf(NO_MOCK, NO_MOCK_REASON)
  23. class BTMPBeaconTestCase(TestCase, LoaderModuleMockMixin):
  24. '''
  25. Test case for salt.beacons.[s]
  26. '''
  27. def setup_loader_modules(self):
  28. return {
  29. btmp: {
  30. '__context__': {'btmp.loc': 2},
  31. '__salt__': {},
  32. }
  33. }
  34. def test_non_list_config(self):
  35. config = {}
  36. ret = btmp.validate(config)
  37. self.assertEqual(ret, (False, 'Configuration for btmp beacon must'
  38. ' be a list.'))
  39. def test_empty_config(self):
  40. config = [{}]
  41. ret = btmp.validate(config)
  42. self.assertEqual(ret, (True, 'Valid beacon configuration'))
  43. def test_no_match(self):
  44. config = [{'users': {'gareth': {'time_range': {'end': '09-22-2017 5pm',
  45. 'start': '09-22-2017 3pm'}}}}
  46. ]
  47. ret = btmp.validate(config)
  48. self.assertEqual(ret, (True, 'Valid beacon configuration'))
  49. with patch('salt.utils.files.fopen', mock_open(b'')) as m_open:
  50. ret = btmp.beacon(config)
  51. call_args = next(six.itervalues(m_open.filehandles))[0].call.args
  52. assert call_args == (btmp.BTMP, 'rb'), call_args
  53. assert ret == [], ret
  54. def test_invalid_users(self):
  55. config = [{'users': ['gareth']}]
  56. ret = btmp.validate(config)
  57. self.assertEqual(ret, (False, 'User configuration for btmp beacon must be a dictionary.'))
  58. def test_invalid_groups(self):
  59. config = [{'groups': ['docker']}]
  60. ret = btmp.validate(config)
  61. self.assertEqual(ret, (False, 'Group configuration for btmp beacon must be a dictionary.'))
  62. def test_default_invalid_time_range(self):
  63. config = [{'defaults': {'time_range': {'start': '3pm'}}}]
  64. ret = btmp.validate(config)
  65. self.assertEqual(ret, (False, 'The time_range parameter for btmp beacon must contain start & end options.'))
  66. def test_users_invalid_time_range(self):
  67. config = [{'users': {'gareth': {'time_range': {'start': '3pm'}}}}]
  68. ret = btmp.validate(config)
  69. self.assertEqual(ret, (False, 'The time_range parameter for btmp beacon must contain start & end options.'))
  70. def test_groups_invalid_time_range(self):
  71. config = [{'groups': {'docker': {'time_range': {'start': '3pm'}}}}]
  72. ret = btmp.validate(config)
  73. self.assertEqual(ret, (False, 'The time_range parameter for btmp beacon must contain start & end options.'))
  74. def test_match(self):
  75. with patch('salt.utils.files.fopen',
  76. mock_open(read_data=raw)):
  77. with patch('struct.unpack',
  78. MagicMock(return_value=pack)):
  79. config = [{'users': {'garet': {}}}]
  80. ret = btmp.validate(config)
  81. self.assertEqual(ret, (True, 'Valid beacon configuration'))
  82. _expected = [{'addr': 1505937373,
  83. 'exit_status': 0,
  84. 'inittab': '',
  85. 'hostname': '::1',
  86. 'PID': 29774,
  87. 'session': 0,
  88. 'user':
  89. 'garet',
  90. 'time': 0,
  91. 'line': 'ssh:notty',
  92. 'type': 6}]
  93. ret = btmp.beacon(config)
  94. self.assertEqual(ret, _expected)
  95. @skipIf(not _TIME_SUPPORTED, 'dateutil.parser is missing.')
  96. def test_match_time(self):
  97. with patch('salt.utils.files.fopen',
  98. mock_open(read_data=raw)):
  99. mock_now = datetime.datetime(2017, 9, 22, 16, 0, 0, 0)
  100. with patch('datetime.datetime', MagicMock()), \
  101. patch('datetime.datetime.now',
  102. MagicMock(return_value=mock_now)):
  103. with patch('struct.unpack',
  104. MagicMock(return_value=pack)):
  105. config = [{'users': {'garet': {'time_range': {'end': '09-22-2017 5pm',
  106. 'start': '09-22-2017 3pm'}}}}
  107. ]
  108. ret = btmp.validate(config)
  109. self.assertEqual(ret, (True, 'Valid beacon configuration'))
  110. _expected = [{'addr': 1505937373,
  111. 'exit_status': 0,
  112. 'inittab': '',
  113. 'hostname': '::1',
  114. 'PID': 29774,
  115. 'session': 0,
  116. 'user':
  117. 'garet',
  118. 'time': 0,
  119. 'line': 'ssh:notty',
  120. 'type': 6}]
  121. ret = btmp.beacon(config)
  122. self.assertEqual(ret, _expected)
  123. def test_match_group(self):
  124. for groupadd in ('salt.modules.aix_group',
  125. 'salt.modules.mac_group',
  126. 'salt.modules.pw_group',
  127. 'salt.modules.solaris_group',
  128. 'salt.modules.win_groupadd'):
  129. mock_group_info = {'passwd': 'x',
  130. 'gid': 100,
  131. 'name': 'users',
  132. 'members': ['garet']}
  133. with patch('salt.utils.files.fopen',
  134. mock_open(read_data=raw)):
  135. with patch('time.time',
  136. MagicMock(return_value=1506121200)):
  137. with patch('struct.unpack',
  138. MagicMock(return_value=pack)):
  139. with patch('{0}.info'.format(groupadd),
  140. new=MagicMock(return_value=mock_group_info)):
  141. config = [{'group': {'users': {'time_range': {'end': '5pm',
  142. 'start': '3pm'}}}}
  143. ]
  144. ret = btmp.validate(config)
  145. self.assertEqual(ret,
  146. (True, 'Valid beacon configuration'))
  147. _expected = [{'addr': 1505937373,
  148. 'exit_status': 0,
  149. 'inittab': '',
  150. 'hostname': '::1',
  151. 'PID': 29774,
  152. 'session': 0,
  153. 'user':
  154. 'garet',
  155. 'time': 0,
  156. 'line': 'ssh:notty',
  157. 'type': 6}]
  158. ret = btmp.beacon(config)
  159. self.assertEqual(ret, _expected)