acl_test.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. # --- BEGIN COPYRIGHT BLOCK ---
  2. # Copyright (C) 2016 Red Hat, Inc.
  3. # All rights reserved.
  4. #
  5. # License: GPL (version 3 or any later version).
  6. # See LICENSE for details.
  7. # --- END COPYRIGHT BLOCK ---
  8. #
  9. import pytest
  10. from ldap.controls.simple import GetEffectiveRightsControl
  11. from lib389.tasks import *
  12. from lib389.utils import *
  13. from lib389.topologies import topology_m2
  14. logging.getLogger(__name__).setLevel(logging.DEBUG)
  15. log = logging.getLogger(__name__)
  16. TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
  17. STAGING_CN = "staged user"
  18. PRODUCTION_CN = "accounts"
  19. EXCEPT_CN = "excepts"
  20. STAGING_DN = "cn=%s,%s" % (STAGING_CN, SUFFIX)
  21. PRODUCTION_DN = "cn=%s,%s" % (PRODUCTION_CN, SUFFIX)
  22. PROD_EXCEPT_DN = "cn=%s,%s" % (EXCEPT_CN, PRODUCTION_DN)
  23. STAGING_PATTERN = "cn=%s*,%s" % (STAGING_CN[:2], SUFFIX)
  24. PRODUCTION_PATTERN = "cn=%s*,%s" % (PRODUCTION_CN[:2], SUFFIX)
  25. BAD_STAGING_PATTERN = "cn=bad*,%s" % (SUFFIX)
  26. BAD_PRODUCTION_PATTERN = "cn=bad*,%s" % (SUFFIX)
  27. BIND_CN = "bind_entry"
  28. BIND_DN = "cn=%s,%s" % (BIND_CN, SUFFIX)
  29. BIND_PW = "password"
  30. NEW_ACCOUNT = "new_account"
  31. MAX_ACCOUNTS = 20
  32. CONFIG_MODDN_ACI_ATTR = "nsslapd-moddn-aci"
  33. SRC_ENTRY_CN = "tuser"
  34. EXT_RDN = "01"
  35. DST_ENTRY_CN = SRC_ENTRY_CN + EXT_RDN
  36. SRC_ENTRY_DN = "cn=%s,%s" % (SRC_ENTRY_CN, SUFFIX)
  37. DST_ENTRY_DN = "cn=%s,%s" % (DST_ENTRY_CN, SUFFIX)
  38. def add_attr(topology_m2, attr_name):
  39. """Adds attribute to the schema"""
  40. ATTR_VALUE = """(NAME '%s' \
  41. DESC 'Attribute filteri-Multi-Valued' \
  42. SYNTAX 1.3.6.1.4.1.1466.115.121.1.27)""" % attr_name
  43. mod = [(ldap.MOD_ADD, 'attributeTypes', ATTR_VALUE)]
  44. try:
  45. topology_m2.ms["master1"].modify_s(DN_SCHEMA, mod)
  46. except ldap.LDAPError as e:
  47. log.fatal('Failed to add attr (%s): error (%s)' % (attr_name,
  48. e.message['desc']))
  49. assert False
  50. @pytest.fixture(params=["lang-ja", "binary", "phonetic"])
  51. def aci_with_attr_subtype(request, topology_m2):
  52. """Adds and deletes an ACI in the DEFAULT_SUFFIX"""
  53. TARGET_ATTR = 'protectedOperation'
  54. USER_ATTR = 'allowedToPerform'
  55. SUBTYPE = request.param
  56. log.info("========Executing test with '%s' subtype========" % SUBTYPE)
  57. log.info(" Add a target attribute")
  58. add_attr(topology_m2, TARGET_ATTR)
  59. log.info(" Add a user attribute")
  60. add_attr(topology_m2, USER_ATTR)
  61. ACI_TARGET = '(targetattr=%s;%s)' % (TARGET_ATTR, SUBTYPE)
  62. ACI_ALLOW = '(version 3.0; acl "test aci for subtypes"; allow (read) '
  63. ACI_SUBJECT = 'userattr = "%s;%s#GROUPDN";)' % (USER_ATTR, SUBTYPE)
  64. ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
  65. log.info(" Add an ACI with attribute subtype")
  66. mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
  67. try:
  68. topology_m2.ms["master1"].modify_s(DEFAULT_SUFFIX, mod)
  69. except ldap.LDAPError as e:
  70. log.fatal('Failed to add ACI: error (%s)' % (e.message['desc']))
  71. assert False
  72. def fin():
  73. log.info(" Finally, delete an ACI with the '%s' subtype" %
  74. SUBTYPE)
  75. mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
  76. try:
  77. topology_m2.ms["master1"].modify_s(DEFAULT_SUFFIX, mod)
  78. except ldap.LDAPError as e:
  79. log.fatal('Failed to delete ACI: error (%s)' % (e.message['desc']))
  80. assert False
  81. request.addfinalizer(fin)
  82. return ACI_BODY
  83. def test_aci_attr_subtype_targetattr(topology_m2, aci_with_attr_subtype):
  84. """Checks, that ACIs allow attribute subtypes in the targetattr keyword
  85. Test description:
  86. 1. Define two attributes in the schema
  87. - first will be a targetattr
  88. - second will be a userattr
  89. 2. Add an ACI with an attribute subtype
  90. - or language subtype
  91. - or binary subtype
  92. - or pronunciation subtype
  93. """
  94. log.info(" Search for the added attribute")
  95. try:
  96. entries = topology_m2.ms["master1"].search_s(DEFAULT_SUFFIX,
  97. ldap.SCOPE_BASE,
  98. '(objectclass=*)', ['aci'])
  99. entry = str(entries[0])
  100. assert aci_with_attr_subtype in entry
  101. log.info(" The added attribute was found")
  102. except ldap.LDAPError as e:
  103. log.fatal('Search failed, error: ' + e.message['desc'])
  104. assert False
  105. def _bind_manager(topology_m2):
  106. topology_m2.ms["master1"].log.info("Bind as %s " % DN_DM)
  107. topology_m2.ms["master1"].simple_bind_s(DN_DM, PASSWORD)
  108. def _bind_normal(topology_m2):
  109. # bind as bind_entry
  110. topology_m2.ms["master1"].log.info("Bind as %s" % BIND_DN)
  111. topology_m2.ms["master1"].simple_bind_s(BIND_DN, BIND_PW)
  112. def _moddn_aci_deny_tree(topology_m2, mod_type=None,
  113. target_from=STAGING_DN, target_to=PROD_EXCEPT_DN):
  114. """It denies the access moddn_to in cn=except,cn=accounts,SUFFIX"""
  115. assert mod_type is not None
  116. ACI_TARGET_FROM = ""
  117. ACI_TARGET_TO = ""
  118. if target_from:
  119. ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
  120. if target_to:
  121. ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
  122. ACI_ALLOW = "(version 3.0; acl \"Deny MODDN to prod_except\"; deny (moddn)"
  123. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  124. ACI_BODY = ACI_TARGET_TO + ACI_TARGET_FROM + ACI_ALLOW + ACI_SUBJECT
  125. mod = [(mod_type, 'aci', ACI_BODY)]
  126. # topology_m2.ms["master1"].modify_s(SUFFIX, mod)
  127. topology_m2.ms["master1"].log.info("Add a DENY aci under %s " % PROD_EXCEPT_DN)
  128. topology_m2.ms["master1"].modify_s(PROD_EXCEPT_DN, mod)
  129. def _write_aci_staging(topology_m2, mod_type=None):
  130. assert mod_type is not None
  131. ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % STAGING_DN
  132. ACI_ALLOW = "(version 3.0; acl \"write staging entries\"; allow (write)"
  133. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  134. ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
  135. mod = [(mod_type, 'aci', ACI_BODY)]
  136. topology_m2.ms["master1"].modify_s(SUFFIX, mod)
  137. def _write_aci_production(topology_m2, mod_type=None):
  138. assert mod_type is not None
  139. ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % PRODUCTION_DN
  140. ACI_ALLOW = "(version 3.0; acl \"write production entries\"; allow (write)"
  141. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  142. ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
  143. mod = [(mod_type, 'aci', ACI_BODY)]
  144. topology_m2.ms["master1"].modify_s(SUFFIX, mod)
  145. def _moddn_aci_staging_to_production(topology_m2, mod_type=None,
  146. target_from=STAGING_DN, target_to=PRODUCTION_DN):
  147. assert mod_type is not None
  148. ACI_TARGET_FROM = ""
  149. ACI_TARGET_TO = ""
  150. if target_from:
  151. ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
  152. if target_to:
  153. ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
  154. ACI_ALLOW = "(version 3.0; acl \"MODDN from staging to production\"; allow (moddn)"
  155. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  156. ACI_BODY = ACI_TARGET_FROM + ACI_TARGET_TO + ACI_ALLOW + ACI_SUBJECT
  157. mod = [(mod_type, 'aci', ACI_BODY)]
  158. topology_m2.ms["master1"].modify_s(SUFFIX, mod)
  159. _write_aci_staging(topology_m2, mod_type=mod_type)
  160. def _moddn_aci_from_production_to_staging(topology_m2, mod_type=None):
  161. assert mod_type is not None
  162. ACI_TARGET = "(target_from = \"ldap:///%s\") (target_to = \"ldap:///%s\")" % (
  163. PRODUCTION_DN, STAGING_DN)
  164. ACI_ALLOW = "(version 3.0; acl \"MODDN from production to staging\"; allow (moddn)"
  165. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  166. ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
  167. mod = [(mod_type, 'aci', ACI_BODY)]
  168. topology_m2.ms["master1"].modify_s(SUFFIX, mod)
  169. _write_aci_production(topology_m2, mod_type=mod_type)
  170. @pytest.fixture(scope="module")
  171. def moddn_setup(topology_m2):
  172. """Creates
  173. - a staging DIT
  174. - a production DIT
  175. - add accounts in staging DIT
  176. - enable ACL logging (commented for performance reason)
  177. """
  178. topology_m2.ms["master1"].log.info("\n\n######## INITIALIZATION ########\n")
  179. # entry used to bind with
  180. topology_m2.ms["master1"].log.info("Add %s" % BIND_DN)
  181. topology_m2.ms["master1"].add_s(Entry((BIND_DN, {
  182. 'objectclass': "top person".split(),
  183. 'sn': BIND_CN,
  184. 'cn': BIND_CN,
  185. 'userpassword': BIND_PW})))
  186. # DIT for staging
  187. topology_m2.ms["master1"].log.info("Add %s" % STAGING_DN)
  188. topology_m2.ms["master1"].add_s(Entry((STAGING_DN, {
  189. 'objectclass': "top organizationalRole".split(),
  190. 'cn': STAGING_CN,
  191. 'description': "staging DIT"})))
  192. # DIT for production
  193. topology_m2.ms["master1"].log.info("Add %s" % PRODUCTION_DN)
  194. topology_m2.ms["master1"].add_s(Entry((PRODUCTION_DN, {
  195. 'objectclass': "top organizationalRole".split(),
  196. 'cn': PRODUCTION_CN,
  197. 'description': "production DIT"})))
  198. # DIT for production/except
  199. topology_m2.ms["master1"].log.info("Add %s" % PROD_EXCEPT_DN)
  200. topology_m2.ms["master1"].add_s(Entry((PROD_EXCEPT_DN, {
  201. 'objectclass': "top organizationalRole".split(),
  202. 'cn': EXCEPT_CN,
  203. 'description': "production except DIT"})))
  204. # enable acl error logging
  205. # mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '128')]
  206. # topology_m2.ms["master1"].modify_s(DN_CONFIG, mod)
  207. # topology_m2.ms["master2"].modify_s(DN_CONFIG, mod)
  208. # add dummy entries in the staging DIT
  209. for cpt in range(MAX_ACCOUNTS):
  210. name = "%s%d" % (NEW_ACCOUNT, cpt)
  211. topology_m2.ms["master1"].add_s(Entry(("cn=%s,%s" % (name, STAGING_DN), {
  212. 'objectclass': "top person".split(),
  213. 'sn': name,
  214. 'cn': name})))
  215. def test_mode_default_add_deny(topology_m2, moddn_setup):
  216. """This test case checks
  217. that the ADD operation fails (no ADD aci on production)
  218. """
  219. topology_m2.ms["master1"].log.info("\n\n######## mode moddn_aci : ADD (should fail) ########\n")
  220. _bind_normal(topology_m2)
  221. #
  222. # First try to add an entry in production => INSUFFICIENT_ACCESS
  223. #
  224. try:
  225. topology_m2.ms["master1"].log.info("Try to add %s" % PRODUCTION_DN)
  226. name = "%s%d" % (NEW_ACCOUNT, 0)
  227. topology_m2.ms["master1"].add_s(Entry(("cn=%s,%s" % (name, PRODUCTION_DN), {
  228. 'objectclass': "top person".split(),
  229. 'sn': name,
  230. 'cn': name})))
  231. assert 0 # this is an error, we should not be allowed to add an entry in production
  232. except Exception as e:
  233. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  234. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  235. def test_mode_default_delete_deny(topology_m2, moddn_setup):
  236. """This test case checks
  237. that the DEL operation fails (no 'delete' aci on production)
  238. """
  239. topology_m2.ms["master1"].log.info("\n\n######## DELETE (should fail) ########\n")
  240. _bind_normal(topology_m2)
  241. #
  242. # Second try to delete an entry in staging => INSUFFICIENT_ACCESS
  243. #
  244. try:
  245. topology_m2.ms["master1"].log.info("Try to delete %s" % STAGING_DN)
  246. name = "%s%d" % (NEW_ACCOUNT, 0)
  247. topology_m2.ms["master1"].delete_s("cn=%s,%s" % (name, STAGING_DN))
  248. assert 0 # this is an error, we should not be allowed to add an entry in production
  249. except Exception as e:
  250. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  251. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  252. @pytest.mark.parametrize("index,tfrom,tto,failure",
  253. [(0, STAGING_DN, PRODUCTION_DN, False),
  254. (1, STAGING_DN, PRODUCTION_DN, False),
  255. (2, STAGING_DN, BAD_PRODUCTION_PATTERN, True),
  256. (3, STAGING_PATTERN, PRODUCTION_DN, False),
  257. (4, BAD_STAGING_PATTERN, PRODUCTION_DN, True),
  258. (5, STAGING_PATTERN, PRODUCTION_PATTERN, False),
  259. (6, None, PRODUCTION_PATTERN, False),
  260. (7, STAGING_PATTERN, None, False),
  261. (8, None, None, False)])
  262. def test_moddn_staging_prod(topology_m2, moddn_setup,
  263. index, tfrom, tto, failure):
  264. """This test case MOVE entry NEW_ACCOUNT0 from staging to prod
  265. target_to/target_from: equality filter
  266. """
  267. topology_m2.ms["master1"].log.info("\n\n######## MOVE staging -> Prod (%s) ########\n" % index)
  268. _bind_normal(topology_m2)
  269. old_rdn = "cn=%s%s" % (NEW_ACCOUNT, index)
  270. old_dn = "%s,%s" % (old_rdn, STAGING_DN)
  271. new_rdn = old_rdn
  272. new_superior = PRODUCTION_DN
  273. #
  274. # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
  275. #
  276. try:
  277. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  278. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  279. assert 0
  280. except AssertionError:
  281. topology_m2.ms["master1"].log.info(
  282. "Exception (not really expected exception but that is fine as it fails to rename)")
  283. except Exception as e:
  284. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  285. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  286. # successfull MOD with the ACI
  287. topology_m2.ms["master1"].log.info("\n\n######## MOVE to and from equality filter ########\n")
  288. _bind_manager(topology_m2)
  289. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_ADD,
  290. target_from=tfrom, target_to=tto)
  291. _bind_normal(topology_m2)
  292. try:
  293. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  294. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  295. except Exception as e:
  296. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  297. if failure:
  298. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  299. # successfull MOD with the both ACI
  300. _bind_manager(topology_m2)
  301. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_DELETE,
  302. target_from=tfrom, target_to=tto)
  303. _bind_normal(topology_m2)
  304. def test_moddn_staging_prod_9(topology_m2, moddn_setup):
  305. """This test case disable the 'moddn' right so a MODDN requires a 'add' right
  306. to be successfull.
  307. It fails to MOVE entry NEW_ACCOUNT9 from staging to prod.
  308. Add a 'add' right to prod.
  309. Then it succeeds to MOVE NEW_ACCOUNT9 from staging to prod.
  310. Then enable the 'moddn' right so a MODDN requires a 'moddn' right
  311. It fails to MOVE entry NEW_ACCOUNT10 from staging to prod.
  312. Add a 'moddn' right to prod.
  313. Then it succeeds to MOVE NEW_ACCOUNT10 from staging to prod.
  314. """
  315. topology_m2.ms["master1"].log.info("\n\n######## MOVE staging -> Prod (9) ########\n")
  316. _bind_normal(topology_m2)
  317. old_rdn = "cn=%s9" % NEW_ACCOUNT
  318. old_dn = "%s,%s" % (old_rdn, STAGING_DN)
  319. new_rdn = old_rdn
  320. new_superior = PRODUCTION_DN
  321. #
  322. # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
  323. #
  324. try:
  325. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  326. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  327. assert 0
  328. except AssertionError:
  329. topology_m2.ms["master1"].log.info(
  330. "Exception (not really expected exception but that is fine as it fails to rename)")
  331. except Exception as e:
  332. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  333. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  334. #############
  335. # Now do tests with no support of moddn aci
  336. #############
  337. topology_m2.ms["master1"].log.info("Disable the moddn right")
  338. _bind_manager(topology_m2)
  339. mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
  340. topology_m2.ms["master1"].modify_s(DN_CONFIG, mod)
  341. # Add the moddn aci that will not be evaluated because of the config flag
  342. topology_m2.ms["master1"].log.info("\n\n######## MOVE to and from equality filter ########\n")
  343. _bind_manager(topology_m2)
  344. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_ADD,
  345. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  346. _bind_normal(topology_m2)
  347. # It will fail because it will test the ADD right
  348. try:
  349. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  350. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  351. assert 0
  352. except AssertionError:
  353. topology_m2.ms["master1"].log.info(
  354. "Exception (not really expected exception but that is fine as it fails to rename)")
  355. except Exception as e:
  356. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  357. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  358. # remove the moddn aci
  359. _bind_manager(topology_m2)
  360. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_DELETE,
  361. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  362. _bind_normal(topology_m2)
  363. #
  364. # add the 'add' right to the production DN
  365. # Then do a successfull moddn
  366. #
  367. ACI_ALLOW = "(version 3.0; acl \"ADD rights to allow moddn\"; allow (add)"
  368. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  369. ACI_BODY = ACI_ALLOW + ACI_SUBJECT
  370. _bind_manager(topology_m2)
  371. mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
  372. topology_m2.ms["master1"].modify_s(PRODUCTION_DN, mod)
  373. _write_aci_staging(topology_m2, mod_type=ldap.MOD_ADD)
  374. _bind_normal(topology_m2)
  375. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  376. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  377. _bind_manager(topology_m2)
  378. mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
  379. topology_m2.ms["master1"].modify_s(PRODUCTION_DN, mod)
  380. _write_aci_staging(topology_m2, mod_type=ldap.MOD_DELETE)
  381. _bind_normal(topology_m2)
  382. #############
  383. # Now do tests with support of moddn aci
  384. #############
  385. topology_m2.ms["master1"].log.info("Enable the moddn right")
  386. _bind_manager(topology_m2)
  387. mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'on')]
  388. topology_m2.ms["master1"].modify_s(DN_CONFIG, mod)
  389. topology_m2.ms["master1"].log.info("\n\n######## MOVE staging -> Prod (10) ########\n")
  390. _bind_normal(topology_m2)
  391. old_rdn = "cn=%s10" % NEW_ACCOUNT
  392. old_dn = "%s,%s" % (old_rdn, STAGING_DN)
  393. new_rdn = old_rdn
  394. new_superior = PRODUCTION_DN
  395. #
  396. # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
  397. #
  398. try:
  399. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  400. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  401. assert 0
  402. except AssertionError:
  403. topology_m2.ms["master1"].log.info(
  404. "Exception (not really expected exception but that is fine as it fails to rename)")
  405. except Exception as e:
  406. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  407. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  408. #
  409. # add the 'add' right to the production DN
  410. # Then do a failing moddn
  411. #
  412. ACI_ALLOW = "(version 3.0; acl \"ADD rights to allow moddn\"; allow (add)"
  413. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  414. ACI_BODY = ACI_ALLOW + ACI_SUBJECT
  415. _bind_manager(topology_m2)
  416. mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
  417. topology_m2.ms["master1"].modify_s(PRODUCTION_DN, mod)
  418. _write_aci_staging(topology_m2, mod_type=ldap.MOD_ADD)
  419. _bind_normal(topology_m2)
  420. try:
  421. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  422. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  423. assert 0
  424. except AssertionError:
  425. topology_m2.ms["master1"].log.info(
  426. "Exception (not really expected exception but that is fine as it fails to rename)")
  427. except Exception as e:
  428. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  429. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  430. _bind_manager(topology_m2)
  431. mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
  432. topology_m2.ms["master1"].modify_s(PRODUCTION_DN, mod)
  433. _write_aci_staging(topology_m2, mod_type=ldap.MOD_DELETE)
  434. _bind_normal(topology_m2)
  435. # Add the moddn aci that will be evaluated because of the config flag
  436. topology_m2.ms["master1"].log.info("\n\n######## MOVE to and from equality filter ########\n")
  437. _bind_manager(topology_m2)
  438. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_ADD,
  439. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  440. _bind_normal(topology_m2)
  441. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  442. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  443. # remove the moddn aci
  444. _bind_manager(topology_m2)
  445. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_DELETE,
  446. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  447. _bind_normal(topology_m2)
  448. def test_moddn_prod_staging(topology_m2, moddn_setup):
  449. """This test checks that we can move ACCOUNT11 from staging to prod
  450. but not move back ACCOUNT11 from prod to staging
  451. """
  452. topology_m2.ms["master1"].log.info("\n\n######## MOVE staging -> Prod (11) ########\n")
  453. _bind_normal(topology_m2)
  454. old_rdn = "cn=%s11" % NEW_ACCOUNT
  455. old_dn = "%s,%s" % (old_rdn, STAGING_DN)
  456. new_rdn = old_rdn
  457. new_superior = PRODUCTION_DN
  458. #
  459. # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
  460. #
  461. try:
  462. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  463. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  464. assert 0
  465. except AssertionError:
  466. topology_m2.ms["master1"].log.info(
  467. "Exception (not really expected exception but that is fine as it fails to rename)")
  468. except Exception as e:
  469. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  470. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  471. # successfull MOD with the ACI
  472. topology_m2.ms["master1"].log.info("\n\n######## MOVE to and from equality filter ########\n")
  473. _bind_manager(topology_m2)
  474. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_ADD,
  475. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  476. _bind_normal(topology_m2)
  477. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  478. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  479. # Now check we can not move back the entry to staging
  480. old_rdn = "cn=%s11" % NEW_ACCOUNT
  481. old_dn = "%s,%s" % (old_rdn, PRODUCTION_DN)
  482. new_rdn = old_rdn
  483. new_superior = STAGING_DN
  484. # add the write right because we want to check the moddn
  485. _bind_manager(topology_m2)
  486. _write_aci_production(topology_m2, mod_type=ldap.MOD_ADD)
  487. _bind_normal(topology_m2)
  488. try:
  489. topology_m2.ms["master1"].log.info("Try to move back MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  490. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  491. assert 0
  492. except AssertionError:
  493. topology_m2.ms["master1"].log.info(
  494. "Exception (not really expected exception but that is fine as it fails to rename)")
  495. except Exception as e:
  496. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  497. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  498. _bind_manager(topology_m2)
  499. _write_aci_production(topology_m2, mod_type=ldap.MOD_DELETE)
  500. _bind_normal(topology_m2)
  501. # successfull MOD with the both ACI
  502. _bind_manager(topology_m2)
  503. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_DELETE,
  504. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  505. _bind_normal(topology_m2)
  506. def test_check_repl_M2_to_M1(topology_m2, moddn_setup):
  507. """Checks that replication is still working M2->M1, using ACCOUNT12"""
  508. topology_m2.ms["master1"].log.info("Bind as %s (M2)" % DN_DM)
  509. topology_m2.ms["master2"].simple_bind_s(DN_DM, PASSWORD)
  510. rdn = "cn=%s12" % NEW_ACCOUNT
  511. dn = "%s,%s" % (rdn, STAGING_DN)
  512. # First wait for the ACCOUNT19 entry being replicated on M2
  513. loop = 0
  514. while loop <= 10:
  515. try:
  516. ent = topology_m2.ms["master2"].getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)")
  517. break
  518. except ldap.NO_SUCH_OBJECT:
  519. time.sleep(1)
  520. loop += 1
  521. assert loop <= 10
  522. attribute = 'description'
  523. tested_value = 'Hello world'
  524. mod = [(ldap.MOD_ADD, attribute, tested_value)]
  525. topology_m2.ms["master1"].log.info("Update (M2) %s (%s)" % (dn, attribute))
  526. topology_m2.ms["master2"].modify_s(dn, mod)
  527. loop = 0
  528. while loop <= 10:
  529. ent = topology_m2.ms["master1"].getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)")
  530. assert ent is not None
  531. if ent.hasAttr(attribute) and (ent.getValue(attribute) == tested_value):
  532. break
  533. time.sleep(1)
  534. loop += 1
  535. assert loop < 10
  536. topology_m2.ms["master1"].log.info("Update %s (%s) replicated on M1" % (dn, attribute))
  537. def test_moddn_staging_prod_except(topology_m2, moddn_setup):
  538. """This test case MOVE entry NEW_ACCOUNT13 from staging to prod
  539. but fails to move entry NEW_ACCOUNT14 from staging to prod_except
  540. """
  541. topology_m2.ms["master1"].log.info("\n\n######## MOVE staging -> Prod (13) ########\n")
  542. _bind_normal(topology_m2)
  543. old_rdn = "cn=%s13" % NEW_ACCOUNT
  544. old_dn = "%s,%s" % (old_rdn, STAGING_DN)
  545. new_rdn = old_rdn
  546. new_superior = PRODUCTION_DN
  547. #
  548. # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
  549. #
  550. try:
  551. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  552. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  553. assert 0
  554. except AssertionError:
  555. topology_m2.ms["master1"].log.info(
  556. "Exception (not really expected exception but that is fine as it fails to rename)")
  557. except Exception as e:
  558. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  559. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  560. # successfull MOD with the ACI
  561. topology_m2.ms["master1"].log.info("\n\n######## MOVE to and from equality filter ########\n")
  562. _bind_manager(topology_m2)
  563. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_ADD,
  564. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  565. _moddn_aci_deny_tree(topology_m2, mod_type=ldap.MOD_ADD)
  566. _bind_normal(topology_m2)
  567. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  568. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  569. #
  570. # Now try to move an entry under except
  571. #
  572. topology_m2.ms["master1"].log.info("\n\n######## MOVE staging -> Prod/Except (14) ########\n")
  573. old_rdn = "cn=%s14" % NEW_ACCOUNT
  574. old_dn = "%s,%s" % (old_rdn, STAGING_DN)
  575. new_rdn = old_rdn
  576. new_superior = PROD_EXCEPT_DN
  577. try:
  578. topology_m2.ms["master1"].log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
  579. topology_m2.ms["master1"].rename_s(old_dn, new_rdn, newsuperior=new_superior)
  580. assert 0
  581. except AssertionError:
  582. topology_m2.ms["master1"].log.info(
  583. "Exception (not really expected exception but that is fine as it fails to rename)")
  584. except Exception as e:
  585. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  586. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  587. # successfull MOD with the both ACI
  588. _bind_manager(topology_m2)
  589. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_DELETE,
  590. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  591. _moddn_aci_deny_tree(topology_m2, mod_type=ldap.MOD_DELETE)
  592. _bind_normal(topology_m2)
  593. def test_mode_default_ger_no_moddn(topology_m2, moddn_setup):
  594. topology_m2.ms["master1"].log.info("\n\n######## mode moddn_aci : GER no moddn ########\n")
  595. request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
  596. msg_id = topology_m2.ms["master1"].search_ext(PRODUCTION_DN,
  597. ldap.SCOPE_SUBTREE,
  598. "objectclass=*",
  599. serverctrls=[request_ctrl])
  600. rtype, rdata, rmsgid, response_ctrl = topology_m2.ms["master1"].result3(msg_id)
  601. # ger={}
  602. value = ''
  603. for dn, attrs in rdata:
  604. topology_m2.ms["master1"].log.info("dn: %s" % dn)
  605. value = attrs['entryLevelRights'][0]
  606. topology_m2.ms["master1"].log.info("######## entryLevelRights: %r" % value)
  607. assert 'n' not in value
  608. def test_mode_default_ger_with_moddn(topology_m2, moddn_setup):
  609. """This test case adds the moddn aci and check ger contains 'n'"""
  610. topology_m2.ms["master1"].log.info("\n\n######## mode moddn_aci: GER with moddn ########\n")
  611. # successfull MOD with the ACI
  612. _bind_manager(topology_m2)
  613. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_ADD,
  614. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  615. _bind_normal(topology_m2)
  616. request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
  617. msg_id = topology_m2.ms["master1"].search_ext(PRODUCTION_DN,
  618. ldap.SCOPE_SUBTREE,
  619. "objectclass=*",
  620. serverctrls=[request_ctrl])
  621. rtype, rdata, rmsgid, response_ctrl = topology_m2.ms["master1"].result3(msg_id)
  622. # ger={}
  623. value = ''
  624. for dn, attrs in rdata:
  625. topology_m2.ms["master1"].log.info("dn: %s" % dn)
  626. value = attrs['entryLevelRights'][0]
  627. topology_m2.ms["master1"].log.info("######## entryLevelRights: %r" % value)
  628. assert 'n' in value
  629. # successfull MOD with the both ACI
  630. _bind_manager(topology_m2)
  631. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_DELETE,
  632. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  633. _bind_normal(topology_m2)
  634. def test_mode_switch_default_to_legacy(topology_m2, moddn_setup):
  635. """This test switch the server from default mode to legacy"""
  636. topology_m2.ms["master1"].log.info("\n\n######## Disable the moddn aci mod ########\n")
  637. _bind_manager(topology_m2)
  638. mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
  639. topology_m2.ms["master1"].modify_s(DN_CONFIG, mod)
  640. def test_mode_legacy_ger_no_moddn1(topology_m2, moddn_setup):
  641. topology_m2.ms["master1"].log.info("\n\n######## mode legacy 1: GER no moddn ########\n")
  642. request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
  643. msg_id = topology_m2.ms["master1"].search_ext(PRODUCTION_DN,
  644. ldap.SCOPE_SUBTREE,
  645. "objectclass=*",
  646. serverctrls=[request_ctrl])
  647. rtype, rdata, rmsgid, response_ctrl = topology_m2.ms["master1"].result3(msg_id)
  648. # ger={}
  649. value = ''
  650. for dn, attrs in rdata:
  651. topology_m2.ms["master1"].log.info("dn: %s" % dn)
  652. value = attrs['entryLevelRights'][0]
  653. topology_m2.ms["master1"].log.info("######## entryLevelRights: %r" % value)
  654. assert 'n' not in value
  655. def test_mode_legacy_ger_no_moddn2(topology_m2, moddn_setup):
  656. topology_m2.ms["master1"].log.info("\n\n######## mode legacy 2: GER no moddn ########\n")
  657. # successfull MOD with the ACI
  658. _bind_manager(topology_m2)
  659. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_ADD,
  660. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  661. _bind_normal(topology_m2)
  662. request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
  663. msg_id = topology_m2.ms["master1"].search_ext(PRODUCTION_DN,
  664. ldap.SCOPE_SUBTREE,
  665. "objectclass=*",
  666. serverctrls=[request_ctrl])
  667. rtype, rdata, rmsgid, response_ctrl = topology_m2.ms["master1"].result3(msg_id)
  668. # ger={}
  669. value = ''
  670. for dn, attrs in rdata:
  671. topology_m2.ms["master1"].log.info("dn: %s" % dn)
  672. value = attrs['entryLevelRights'][0]
  673. topology_m2.ms["master1"].log.info("######## entryLevelRights: %r" % value)
  674. assert 'n' not in value
  675. # successfull MOD with the both ACI
  676. _bind_manager(topology_m2)
  677. _moddn_aci_staging_to_production(topology_m2, mod_type=ldap.MOD_DELETE,
  678. target_from=STAGING_DN, target_to=PRODUCTION_DN)
  679. _bind_normal(topology_m2)
  680. def test_mode_legacy_ger_with_moddn(topology_m2, moddn_setup):
  681. topology_m2.ms["master1"].log.info("\n\n######## mode legacy : GER with moddn ########\n")
  682. # being allowed to read/write the RDN attribute use to allow the RDN
  683. ACI_TARGET = "(target = \"ldap:///%s\")(targetattr=\"cn\")" % (PRODUCTION_DN)
  684. ACI_ALLOW = "(version 3.0; acl \"MODDN production changing the RDN attribute\"; allow (read,search,write)"
  685. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  686. ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
  687. # successfull MOD with the ACI
  688. _bind_manager(topology_m2)
  689. mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
  690. topology_m2.ms["master1"].modify_s(SUFFIX, mod)
  691. _bind_normal(topology_m2)
  692. request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
  693. msg_id = topology_m2.ms["master1"].search_ext(PRODUCTION_DN,
  694. ldap.SCOPE_SUBTREE,
  695. "objectclass=*",
  696. serverctrls=[request_ctrl])
  697. rtype, rdata, rmsgid, response_ctrl = topology_m2.ms["master1"].result3(msg_id)
  698. # ger={}
  699. value = ''
  700. for dn, attrs in rdata:
  701. topology_m2.ms["master1"].log.info("dn: %s" % dn)
  702. value = attrs['entryLevelRights'][0]
  703. topology_m2.ms["master1"].log.info("######## entryLevelRights: %r" % value)
  704. assert 'n' in value
  705. # successfull MOD with the both ACI
  706. _bind_manager(topology_m2)
  707. mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
  708. topology_m2.ms["master1"].modify_s(SUFFIX, mod)
  709. # _bind_normal(topology_m2)
  710. @pytest.fixture(scope="module")
  711. def rdn_write_setup(topology_m2):
  712. topology_m2.ms["master1"].log.info("\n\n######## Add entry tuser ########\n")
  713. topology_m2.ms["master1"].add_s(Entry((SRC_ENTRY_DN, {
  714. 'objectclass': "top person".split(),
  715. 'sn': SRC_ENTRY_CN,
  716. 'cn': SRC_ENTRY_CN})))
  717. def test_rdn_write_get_ger(topology_m2, rdn_write_setup):
  718. ANONYMOUS_DN = ""
  719. topology_m2.ms["master1"].log.info("\n\n######## GER rights for anonymous ########\n")
  720. request_ctrl = GetEffectiveRightsControl(criticality=True,
  721. authzId="dn:" + ANONYMOUS_DN)
  722. msg_id = topology_m2.ms["master1"].search_ext(SUFFIX,
  723. ldap.SCOPE_SUBTREE,
  724. "objectclass=*",
  725. serverctrls=[request_ctrl])
  726. rtype, rdata, rmsgid, response_ctrl = topology_m2.ms["master1"].result3(msg_id)
  727. value = ''
  728. for dn, attrs in rdata:
  729. topology_m2.ms["master1"].log.info("dn: %s" % dn)
  730. for value in attrs['entryLevelRights']:
  731. topology_m2.ms["master1"].log.info("######## entryLevelRights: %r" % value)
  732. assert 'n' not in value
  733. def test_rdn_write_modrdn_anonymous(topology_m2, rdn_write_setup):
  734. ANONYMOUS_DN = ""
  735. topology_m2.ms["master1"].close()
  736. topology_m2.ms["master1"].binddn = ANONYMOUS_DN
  737. topology_m2.ms["master1"].open()
  738. msg_id = topology_m2.ms["master1"].search_ext("", ldap.SCOPE_BASE, "objectclass=*")
  739. rtype, rdata, rmsgid, response_ctrl = topology_m2.ms["master1"].result3(msg_id)
  740. for dn, attrs in rdata:
  741. topology_m2.ms["master1"].log.info("dn: %s" % dn)
  742. for attr in attrs:
  743. topology_m2.ms["master1"].log.info("######## %r: %r" % (attr, attrs[attr]))
  744. try:
  745. topology_m2.ms["master1"].rename_s(SRC_ENTRY_DN, "cn=%s" % DST_ENTRY_CN, delold=True)
  746. except Exception as e:
  747. topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__)
  748. isinstance(e, ldap.INSUFFICIENT_ACCESS)
  749. try:
  750. topology_m2.ms["master1"].getEntry(DST_ENTRY_DN, ldap.SCOPE_BASE, "objectclass=*")
  751. assert False
  752. except Exception as e:
  753. topology_m2.ms["master1"].log.info("The entry was not renamed (expected)")
  754. isinstance(e, ldap.NO_SUCH_OBJECT)
  755. _bind_manager(topology_m2)
  756. if __name__ == '__main__':
  757. # Run isolated
  758. # -s for DEBUG mode
  759. CURRENT_FILE = os.path.realpath(__file__)
  760. pytest.main("-s %s" % CURRENT_FILE)