test_win_runas.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import, unicode_literals
  3. import textwrap
  4. import subprocess
  5. import socket
  6. import inspect
  7. import io
  8. # Service manager imports
  9. import sys
  10. import os
  11. import logging
  12. import threading
  13. import traceback
  14. import time
  15. import yaml
  16. from tests.support.case import ModuleCase
  17. from tests.support.mock import Mock
  18. from tests.support.unit import skipIf
  19. from tests.support.runtests import RUNTIME_VARS
  20. from tests.support.helpers import (
  21. with_system_user,
  22. )
  23. import salt.utils.files
  24. import salt.utils.win_runas
  25. import salt.ext.six
  26. try:
  27. import win32service
  28. import win32serviceutil
  29. import win32event
  30. import servicemanager
  31. import win32api
  32. CODE_DIR = win32api.GetLongPathName(RUNTIME_VARS.CODE_DIR)
  33. HAS_WIN32 = True
  34. except ImportError:
  35. # Mock win32serviceutil object to avoid
  36. # a stacktrace in the _ServiceManager class
  37. win32serviceutil = Mock()
  38. HAS_WIN32 = False
  39. logger = logging.getLogger(__name__)
  40. PASSWORD = 'P@ssW0rd'
  41. NOPRIV_STDERR = 'ERROR: Logged-on user does not have administrative privilege.\n'
  42. PRIV_STDOUT = (
  43. '\nINFO: The system global flag \'maintain objects list\' needs\n '
  44. 'to be enabled to see local opened files.\n See Openfiles '
  45. '/? for more information.\n\n\nFiles opened remotely via local share '
  46. 'points:\n---------------------------------------------\n\n'
  47. 'INFO: No shared open files found.\n'
  48. )
  49. if HAS_WIN32:
  50. RUNAS_PATH = os.path.abspath(os.path.join(CODE_DIR, 'runas.py'))
  51. RUNAS_OUT = os.path.abspath(os.path.join(CODE_DIR, 'runas.out'))
  52. def default_target(service, *args, **kwargs):
  53. while service.active:
  54. time.sleep(service.timeout)
  55. class _ServiceManager(win32serviceutil.ServiceFramework):
  56. '''
  57. A windows service manager
  58. '''
  59. _svc_name_ = "Service Manager"
  60. _svc_display_name_ = "Service Manager"
  61. _svc_description_ = "A Service Manager"
  62. run_in_foreground = False
  63. target = default_target
  64. def __init__(self, args, target=None, timeout=60, active=True):
  65. win32serviceutil.ServiceFramework.__init__(self, args)
  66. self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
  67. self.timeout = timeout
  68. self.active = active
  69. if target is not None:
  70. self.target = target
  71. @classmethod
  72. def log_error(cls, msg):
  73. if cls.run_in_foreground:
  74. logger.error(msg)
  75. servicemanager.LogErrorMsg(msg)
  76. @classmethod
  77. def log_info(cls, msg):
  78. if cls.run_in_foreground:
  79. logger.info(msg)
  80. servicemanager.LogInfoMsg(msg)
  81. @classmethod
  82. def log_exception(cls, msg):
  83. if cls.run_in_foreground:
  84. logger.exception(msg)
  85. exc_info = sys.exc_info()
  86. tb = traceback.format_tb(exc_info[2])
  87. servicemanager.LogErrorMsg("{} {} {}".format(msg, exc_info[1], tb))
  88. @property
  89. def timeout_ms(self):
  90. return self.timeout * 1000
  91. def SvcStop(self):
  92. """
  93. Stop the service by; terminating any subprocess call, notify
  94. windows internals of the stop event, set the instance's active
  95. attribute to 'False' so the run loops stop.
  96. """
  97. self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
  98. win32event.SetEvent(self.hWaitStop)
  99. self.active = False
  100. def SvcDoRun(self):
  101. """
  102. Run the monitor in a separete thread so the main thread is
  103. free to react to events sent to the windows service.
  104. """
  105. servicemanager.LogMsg(
  106. servicemanager.EVENTLOG_INFORMATION_TYPE,
  107. servicemanager.PYS_SERVICE_STARTED,
  108. (self._svc_name_, ''),
  109. )
  110. self.log_info("Starting Service {}".format(self._svc_name_))
  111. monitor_thread = threading.Thread(target=self.target_thread)
  112. monitor_thread.start()
  113. while self.active:
  114. rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout_ms)
  115. if rc == win32event.WAIT_OBJECT_0:
  116. # Stop signal encountered
  117. self.log_info("Stopping Service")
  118. break
  119. if not monitor_thread.is_alive():
  120. self.log_info("Update Thread Died, Stopping Service")
  121. break
  122. def target_thread(self, *args, **kwargs):
  123. """
  124. Target Thread, handles any exception in the target method and
  125. logs them.
  126. """
  127. self.log_info("Monitor")
  128. try:
  129. self.target(self, *args, **kwargs)
  130. except Exception as exc: # pylint: disable=broad-except
  131. # TODO: Add traceback info to windows event log objects
  132. self.log_exception("Exception In Target")
  133. @classmethod
  134. def install(cls, username=None, password=None, start_type=None):
  135. if hasattr(cls, '_svc_reg_class_'):
  136. svc_class = cls._svc_reg_class_
  137. else:
  138. svc_class = win32serviceutil.GetServiceClassString(cls)
  139. win32serviceutil.InstallService(
  140. svc_class,
  141. cls._svc_name_,
  142. cls._svc_display_name_,
  143. description=cls._svc_description_,
  144. userName=username,
  145. password=password,
  146. startType=start_type,
  147. )
  148. @classmethod
  149. def remove(cls):
  150. win32serviceutil.RemoveService(
  151. cls._svc_name_
  152. )
  153. @classmethod
  154. def start(cls):
  155. win32serviceutil.StartService(
  156. cls._svc_name_
  157. )
  158. @classmethod
  159. def restart(cls):
  160. win32serviceutil.RestartService(
  161. cls._svc_name_
  162. )
  163. @classmethod
  164. def stop(cls):
  165. win32serviceutil.StopService(
  166. cls._svc_name_
  167. )
  168. def service_class_factory(cls_name, name, target=default_target, display_name='', description='', run_in_foreground=False):
  169. frm = inspect.stack()[1]
  170. mod = inspect.getmodule(frm[0])
  171. if salt.ext.six.PY2:
  172. cls_name = cls_name.encode()
  173. return type(
  174. cls_name,
  175. (_ServiceManager, object),
  176. {
  177. '__module__': mod.__name__,
  178. '_svc_name_': name,
  179. '_svc_display_name_': display_name or name,
  180. '_svc_description_': description,
  181. 'run_in_foreground': run_in_foreground,
  182. 'target': target,
  183. },
  184. )
  185. if HAS_WIN32:
  186. test_service = service_class_factory('test_service', 'test service')
  187. SERVICE_SOURCE = '''
  188. from __future__ import absolute_import, unicode_literals
  189. import logging
  190. logger = logging.getLogger()
  191. logging.basicConfig(level=logging.DEBUG, format="%(message)s")
  192. from tests.integration.utils.test_win_runas import service_class_factory
  193. import salt.utils.win_runas
  194. import sys
  195. import yaml
  196. OUTPUT = {}
  197. USERNAME = '{}'
  198. PASSWORD = '{}'
  199. def target(service, *args, **kwargs):
  200. service.log_info("target start")
  201. if PASSWORD:
  202. ret = salt.utils.win_runas.runas(
  203. 'cmd.exe /C OPENFILES',
  204. username=USERNAME,
  205. password=PASSWORD,
  206. )
  207. else:
  208. ret = salt.utils.win_runas.runas(
  209. 'cmd.exe /C OPENFILES',
  210. username=USERNAME,
  211. )
  212. service.log_info("win_runas returned %s" % ret)
  213. with open(OUTPUT, 'w') as fp:
  214. yaml.dump(ret, fp)
  215. service.log_info("target stop")
  216. # This class will get imported and run as the service
  217. test_service = service_class_factory('test_service', 'test service', target=target)
  218. if __name__ == '__main__':
  219. try:
  220. test_service.stop()
  221. except Exception as exc: # pylint: disable=broad-except
  222. logger.debug("stop service failed, this is ok.")
  223. try:
  224. test_service.remove()
  225. except Exception as exc: # pylint: disable=broad-except
  226. logger.debug("remove service failed, this os ok.")
  227. test_service.install()
  228. sys.exit(0)
  229. '''
  230. def wait_for_service(name, timeout=200):
  231. start = time.time()
  232. while True:
  233. status = win32serviceutil.QueryServiceStatus(name)
  234. if status[1] == win32service.SERVICE_STOPPED:
  235. break
  236. if time.time() - start > timeout:
  237. raise TimeoutError("Timeout waiting for service") # pylint: disable=undefined-variable
  238. time.sleep(.3)
  239. @skipIf(not HAS_WIN32, 'This test runs only on windows.')
  240. class RunAsTest(ModuleCase):
  241. @classmethod
  242. def setUpClass(cls):
  243. super(RunAsTest, cls).setUpClass()
  244. cls.hostname = socket.gethostname()
  245. @with_system_user('test-runas', on_existing='delete', delete=True,
  246. password=PASSWORD)
  247. def test_runas(self, username):
  248. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, PASSWORD)
  249. self.assertEqual(ret['stdout'], '')
  250. self.assertEqual(ret['stderr'], NOPRIV_STDERR)
  251. self.assertEqual(ret['retcode'], 1)
  252. @with_system_user('test-runas', on_existing='delete', delete=True,
  253. password=PASSWORD)
  254. def test_runas_no_pass(self, username):
  255. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)
  256. self.assertEqual(ret['stdout'], '')
  257. self.assertEqual(ret['stderr'], NOPRIV_STDERR)
  258. self.assertEqual(ret['retcode'], 1)
  259. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  260. password=PASSWORD, groups=['Administrators'])
  261. def test_runas_admin(self, username):
  262. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, PASSWORD)
  263. self.assertEqual(ret['stdout'], PRIV_STDOUT)
  264. self.assertEqual(ret['stderr'], '')
  265. self.assertEqual(ret['retcode'], 0)
  266. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  267. password=PASSWORD, groups=['Administrators'])
  268. def test_runas_admin_no_pass(self, username):
  269. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)
  270. self.assertEqual(ret['stdout'], PRIV_STDOUT)
  271. self.assertEqual(ret['stderr'], '')
  272. self.assertEqual(ret['retcode'], 0)
  273. def test_runas_system_user(self):
  274. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'SYSTEM')
  275. self.assertEqual(ret['stdout'], PRIV_STDOUT)
  276. self.assertEqual(ret['stderr'], '')
  277. self.assertEqual(ret['retcode'], 0)
  278. def test_runas_network_service(self):
  279. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'NETWORK SERVICE')
  280. self.assertEqual(ret['stdout'], '')
  281. self.assertEqual(ret['stderr'], NOPRIV_STDERR)
  282. self.assertEqual(ret['retcode'], 1)
  283. def test_runas_local_service(self):
  284. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'LOCAL SERVICE')
  285. self.assertEqual(ret['stdout'], '')
  286. self.assertEqual(ret['stderr'], NOPRIV_STDERR)
  287. self.assertEqual(ret['retcode'], 1)
  288. @with_system_user('test-runas', on_existing='delete', delete=True,
  289. password=PASSWORD)
  290. def test_runas_winrs(self, username):
  291. runaspy = textwrap.dedent('''
  292. import sys
  293. import salt.utils.win_runas
  294. username = '{}'
  295. password = '{}'
  296. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, password)['retcode'])
  297. '''.format(username, PASSWORD))
  298. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  299. fp.write(runaspy)
  300. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  301. self.hostname, RUNAS_PATH), shell=True)
  302. self.assertEqual(ret, 1)
  303. @with_system_user('test-runas', on_existing='delete', delete=True,
  304. password=PASSWORD)
  305. def test_runas_winrs_no_pass(self, username):
  306. runaspy = textwrap.dedent('''
  307. import sys
  308. import salt.utils.win_runas
  309. username = '{}'
  310. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)['retcode'])
  311. '''.format(username))
  312. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  313. fp.write(runaspy)
  314. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  315. self.hostname, RUNAS_PATH), shell=True)
  316. self.assertEqual(ret, 1)
  317. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  318. password=PASSWORD, groups=['Administrators'])
  319. def test_runas_winrs_admin(self, username):
  320. runaspy = textwrap.dedent('''
  321. import sys
  322. import salt.utils.win_runas
  323. username = '{}'
  324. password = '{}'
  325. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, password)['retcode'])
  326. '''.format(username, PASSWORD))
  327. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  328. fp.write(runaspy)
  329. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  330. self.hostname, RUNAS_PATH), shell=True)
  331. self.assertEqual(ret, 0)
  332. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  333. password=PASSWORD, groups=['Administrators'])
  334. def test_runas_winrs_admin_no_pass(self, username):
  335. runaspy = textwrap.dedent('''
  336. import sys
  337. import salt.utils.win_runas
  338. username = '{}'
  339. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)['retcode'])
  340. '''.format(username))
  341. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  342. fp.write(runaspy)
  343. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  344. self.hostname, RUNAS_PATH), shell=True)
  345. self.assertEqual(ret, 0)
  346. def test_runas_winrs_system_user(self):
  347. runaspy = textwrap.dedent('''
  348. import sys
  349. import salt.utils.win_runas
  350. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'SYSTEM')['retcode'])
  351. ''')
  352. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  353. fp.write(runaspy)
  354. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  355. self.hostname, RUNAS_PATH), shell=True)
  356. self.assertEqual(ret, 0)
  357. def test_runas_winrs_network_service_user(self):
  358. runaspy = textwrap.dedent('''
  359. import sys
  360. import salt.utils.win_runas
  361. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'NETWORK SERVICE')['retcode'])
  362. ''')
  363. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  364. fp.write(runaspy)
  365. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  366. self.hostname, RUNAS_PATH), shell=True)
  367. self.assertEqual(ret, 1)
  368. def test_runas_winrs_local_service_user(self):
  369. runaspy = textwrap.dedent('''
  370. import sys
  371. import salt.utils.win_runas
  372. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'LOCAL SERVICE')['retcode'])
  373. ''')
  374. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  375. fp.write(runaspy)
  376. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  377. self.hostname, RUNAS_PATH), shell=True)
  378. self.assertEqual(ret, 1)
  379. @with_system_user('test-runas', on_existing='delete', delete=True,
  380. password=PASSWORD)
  381. def test_runas_powershell_remoting(self, username):
  382. psrp_wrap = (
  383. 'powershell Invoke-Command -ComputerName {} -ScriptBlock {{ {} }}'
  384. )
  385. runaspy = textwrap.dedent('''
  386. import sys
  387. import salt.utils.win_runas
  388. username = '{}'
  389. password = '{}'
  390. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, password)['retcode'])
  391. '''.format(username, PASSWORD))
  392. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  393. fp.write(runaspy)
  394. cmd = 'python.exe {}'.format(RUNAS_PATH)
  395. ret = subprocess.call(
  396. psrp_wrap.format(self.hostname, cmd),
  397. shell=True
  398. )
  399. self.assertEqual(ret, 1)
  400. @with_system_user('test-runas', on_existing='delete', delete=True,
  401. password=PASSWORD)
  402. def test_runas_powershell_remoting_no_pass(self, username):
  403. psrp_wrap = (
  404. 'powershell Invoke-Command -ComputerName {} -ScriptBlock {{ {} }}'
  405. )
  406. runaspy = textwrap.dedent('''
  407. import sys
  408. import salt.utils.win_runas
  409. username = '{}'
  410. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)['retcode'])
  411. '''.format(username))
  412. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  413. fp.write(runaspy)
  414. cmd = 'python.exe {}'.format(RUNAS_PATH)
  415. ret = subprocess.call(
  416. psrp_wrap.format(self.hostname, cmd),
  417. shell=True
  418. )
  419. self.assertEqual(ret, 1)
  420. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  421. password=PASSWORD, groups=['Administrators'])
  422. def test_runas_powershell_remoting_admin(self, username):
  423. psrp_wrap = (
  424. 'powershell Invoke-Command -ComputerName {} -ScriptBlock {{ {} }}; exit $LASTEXITCODE'
  425. )
  426. runaspy = textwrap.dedent('''
  427. import sys
  428. import salt.utils.win_runas
  429. username = '{}'
  430. password = '{}'
  431. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, password)
  432. sys.exit(ret['retcode'])
  433. '''.format(username, PASSWORD))
  434. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  435. fp.write(runaspy)
  436. cmd = 'python.exe {}; exit $LASTEXITCODE'.format(RUNAS_PATH)
  437. ret = subprocess.call(
  438. psrp_wrap.format(self.hostname, cmd),
  439. shell=True
  440. )
  441. self.assertEqual(ret, 0)
  442. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  443. password=PASSWORD, groups=['Administrators'])
  444. def test_runas_powershell_remoting_admin_no_pass(self, username):
  445. psrp_wrap = (
  446. 'powershell Invoke-Command -ComputerName {} -ScriptBlock {{ {} }}; exit $LASTEXITCODE'
  447. )
  448. runaspy = textwrap.dedent('''
  449. import sys
  450. import salt.utils.win_runas
  451. username = '{}'
  452. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)['retcode'])
  453. '''.format(username))
  454. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  455. fp.write(runaspy)
  456. cmd = 'python.exe {}; exit $LASTEXITCODE'.format(RUNAS_PATH)
  457. ret = subprocess.call(
  458. psrp_wrap.format(self.hostname, cmd),
  459. shell=True
  460. )
  461. self.assertEqual(ret, 0)
  462. @with_system_user('test-runas', on_existing='delete', delete=True,
  463. password=PASSWORD)
  464. def test_runas_service(self, username, timeout=200):
  465. if os.path.exists(RUNAS_OUT):
  466. os.remove(RUNAS_OUT)
  467. assert not os.path.exists(RUNAS_OUT)
  468. runaspy = SERVICE_SOURCE.format(repr(RUNAS_OUT), username, PASSWORD)
  469. with io.open(RUNAS_PATH, 'w', encoding='utf-8') as fp:
  470. fp.write(runaspy)
  471. cmd = 'python.exe {}'.format(RUNAS_PATH)
  472. ret = subprocess.call(
  473. cmd,
  474. shell=True
  475. )
  476. self.assertEqual(ret, 0)
  477. win32serviceutil.StartService('test service')
  478. wait_for_service('test service')
  479. with salt.utils.files.fopen(RUNAS_OUT, 'r') as fp:
  480. ret = yaml.load(fp)
  481. assert ret['retcode'] == 1, ret
  482. @with_system_user('test-runas', on_existing='delete', delete=True,
  483. password=PASSWORD)
  484. def test_runas_service_no_pass(self, username, timeout=200):
  485. if os.path.exists(RUNAS_OUT):
  486. os.remove(RUNAS_OUT)
  487. assert not os.path.exists(RUNAS_OUT)
  488. runaspy = SERVICE_SOURCE.format(repr(RUNAS_OUT), username, '')
  489. with io.open(RUNAS_PATH, 'w', encoding='utf-8') as fp:
  490. fp.write(runaspy)
  491. cmd = 'python.exe {}'.format(RUNAS_PATH)
  492. ret = subprocess.call(
  493. cmd,
  494. shell=True
  495. )
  496. self.assertEqual(ret, 0)
  497. win32serviceutil.StartService('test service')
  498. wait_for_service('test service')
  499. with salt.utils.files.fopen(RUNAS_OUT, 'r') as fp:
  500. ret = yaml.load(fp)
  501. assert ret['retcode'] == 1, ret
  502. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  503. password=PASSWORD, groups=['Administrators'])
  504. def test_runas_service_admin(self, username, timeout=200):
  505. if os.path.exists(RUNAS_OUT):
  506. os.remove(RUNAS_OUT)
  507. assert not os.path.exists(RUNAS_OUT)
  508. runaspy = SERVICE_SOURCE.format(repr(RUNAS_OUT), username, PASSWORD)
  509. with io.open(RUNAS_PATH, 'w', encoding='utf-8') as fp:
  510. fp.write(runaspy)
  511. cmd = 'python.exe {}'.format(RUNAS_PATH)
  512. ret = subprocess.call(
  513. cmd,
  514. shell=True
  515. )
  516. self.assertEqual(ret, 0)
  517. win32serviceutil.StartService('test service')
  518. wait_for_service('test service')
  519. with salt.utils.files.fopen(RUNAS_OUT, 'r') as fp:
  520. ret = yaml.load(fp)
  521. assert ret['retcode'] == 0, ret
  522. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  523. password=PASSWORD, groups=['Administrators'])
  524. def test_runas_service_admin_no_pass(self, username, timeout=200):
  525. if os.path.exists(RUNAS_OUT):
  526. os.remove(RUNAS_OUT)
  527. assert not os.path.exists(RUNAS_OUT)
  528. runaspy = SERVICE_SOURCE.format(repr(RUNAS_OUT), username, '')
  529. with io.open(RUNAS_PATH, 'w', encoding='utf-8') as fp:
  530. fp.write(runaspy)
  531. cmd = 'python.exe {}'.format(RUNAS_PATH)
  532. ret = subprocess.call(
  533. cmd,
  534. shell=True
  535. )
  536. self.assertEqual(ret, 0)
  537. win32serviceutil.StartService('test service')
  538. wait_for_service('test service')
  539. with salt.utils.files.fopen(RUNAS_OUT, 'r') as fp:
  540. ret = yaml.load(fp)
  541. assert ret['retcode'] == 0, ret
  542. def test_runas_service_system_user(self):
  543. if os.path.exists(RUNAS_OUT):
  544. os.remove(RUNAS_OUT)
  545. assert not os.path.exists(RUNAS_OUT)
  546. runaspy = SERVICE_SOURCE.format(repr(RUNAS_OUT), 'SYSTEM', '')
  547. with io.open(RUNAS_PATH, 'w', encoding='utf-8') as fp:
  548. fp.write(runaspy)
  549. cmd = 'python.exe {}'.format(RUNAS_PATH)
  550. ret = subprocess.call(
  551. cmd,
  552. shell=True
  553. )
  554. self.assertEqual(ret, 0)
  555. win32serviceutil.StartService('test service')
  556. wait_for_service('test service')
  557. with salt.utils.files.fopen(RUNAS_OUT, 'r') as fp:
  558. ret = yaml.load(fp)
  559. assert ret['retcode'] == 0, ret