test_btmp.py 10 KB

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