regression_test.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. # --- BEGIN COPYRIGHT BLOCK ---
  2. # Copyright (C) 2017 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 logging
  10. import pytest
  11. import os
  12. import time
  13. import ldap
  14. import subprocess
  15. from random import sample
  16. from lib389.utils import ds_is_older, ensure_list_bytes, ensure_bytes
  17. from lib389.topologies import topology_m1h1c1 as topo
  18. from lib389._constants import *
  19. from lib389.plugins import MemberOfPlugin
  20. from lib389 import agreement, Entry
  21. from lib389.idm.user import UserAccount, UserAccounts, TEST_USER_PROPERTIES
  22. from lib389.idm.group import Groups, Group
  23. from lib389.topologies import topology_m2 as topo_m2
  24. from lib389.replica import Replicas
  25. # Skip on older versions
  26. pytestmark = pytest.mark.skipif(ds_is_older('1.3.7'), reason="Not implemented")
  27. USER_CN = 'user_'
  28. GROUP_CN = 'group1'
  29. DEBUGGING = os.getenv("DEBUGGING", default=False)
  30. if DEBUGGING:
  31. logging.getLogger(__name__).setLevel(logging.DEBUG)
  32. else:
  33. logging.getLogger(__name__).setLevel(logging.INFO)
  34. log = logging.getLogger(__name__)
  35. def add_users(topo_m2, users_num, suffix):
  36. """Add users to the default suffix
  37. Return the list of added user DNs.
  38. """
  39. users_list = []
  40. users = UserAccounts(topo_m2.ms["master1"], suffix, rdn=None)
  41. log.info('Adding %d users' % users_num)
  42. for num in sample(range(1000), users_num):
  43. num_ran = int(round(num))
  44. USER_NAME = 'test%05d' % num_ran
  45. user = users.create(properties={
  46. 'uid': USER_NAME,
  47. 'sn': USER_NAME,
  48. 'cn': USER_NAME,
  49. 'uidNumber': '%s' % num_ran,
  50. 'gidNumber': '%s' % num_ran,
  51. 'homeDirectory': '/home/%s' % USER_NAME,
  52. 'mail': '%[email protected]' % USER_NAME,
  53. 'userpassword': 'pass%s' % num_ran,
  54. })
  55. users_list.append(user)
  56. return users_list
  57. def config_memberof(server):
  58. # Configure fractional to prevent total init to send memberof
  59. memberof = MemberOfPlugin(server)
  60. memberof.enable()
  61. memberof.set_autoaddoc('nsMemberOf')
  62. server.restart()
  63. ents = server.agreement.list(suffix=DEFAULT_SUFFIX)
  64. for ent in ents:
  65. log.info('update %s to add nsDS5ReplicatedAttributeListTotal' % ent.dn)
  66. server.agreement.setProperties(agmnt_dn=ents[0].dn,
  67. properties={RA_FRAC_EXCLUDE:'(objectclass=*) $ EXCLUDE memberOf',
  68. RA_FRAC_EXCLUDE_TOTAL_UPDATE:'(objectclass=*) $ EXCLUDE '})
  69. def send_updates_now(server):
  70. ents = server.agreement.list(suffix=DEFAULT_SUFFIX)
  71. for ent in ents:
  72. server.agreement.pause(ent.dn)
  73. server.agreement.resume(ent.dn)
  74. def _find_memberof(server, member_dn, group_dn):
  75. #To get the specific server's (M1, C1 and H1) user and group
  76. user = UserAccount(server, member_dn)
  77. assert user.exists()
  78. group = Group(server, group_dn)
  79. assert group.exists()
  80. #test that the user entry should have memberof attribute with sepecified group dn value
  81. assert group._dn in user.get_attr_vals_utf8('memberOf')
  82. @pytest.mark.bz1352121
  83. def test_memberof_with_repl(topo):
  84. """Test that we allowed to enable MemberOf plugin in dedicated consumer
  85. :id: 60c11636-55a1-4704-9e09-2c6bcc828de4
  86. :setup: 1 Master - 1 Hub - 1 Consumer
  87. :steps:
  88. 1. Configure replication to EXCLUDE memberof
  89. 2. Enable memberof plugin
  90. 3. Create users/groups
  91. 4. Make user_0 member of group_0
  92. 5. Checks that user_0 is memberof group_0 on M,H,C
  93. 6. Make group_0 member of group_1 (nest group)
  94. 7. Checks that user_0 is memberof group_0 and group_1 on M,H,C
  95. 8. Check group_0 is memberof group_1 on M,H,C
  96. 9. Remove group_0 from group_1
  97. 10. Check group_0 and user_0 are NOT memberof group_1 on M,H,C
  98. 11. Remove user_0 from group_0
  99. 12. Check user_0 is not memberof group_0 and group_1 on M,H,C
  100. 13. Disable memberof on C
  101. 14. make user_0 member of group_1
  102. 15. Checks that user_0 is memberof group_0 on M,H but not on C
  103. 16. Enable memberof on C
  104. 17. Checks that user_0 is memberof group_0 on M,H but not on C
  105. 18. Run memberof fixup task
  106. 19. Checks that user_0 is memberof group_0 on M,H,C
  107. :expectedresults:
  108. 1. Configuration should be successful
  109. 2. Plugin should be enabled
  110. 3. Users and groups should be created
  111. 4. user_0 should be member of group_0
  112. 5. user_0 should be memberof group_0 on M,H,C
  113. 6. group_0 should be member of group_1
  114. 7. user_0 should be memberof group_0 and group_1 on M,H,C
  115. 8. group_0 should be memberof group_1 on M,H,C
  116. 9. group_0 from group_1 removal should be successful
  117. 10. group_0 and user_0 should not be memberof group_1 on M,H,C
  118. 11. user_0 from group_0 remove should be successful
  119. 12. user_0 should not be memberof group_0 and group_1 on M,H,C
  120. 13. memberof should be disabled on C
  121. 14. user_0 should be member of group_1
  122. 15. user_0 should be memberof group_0 on M,H and should not on C
  123. 16. Enable memberof on C should be successful
  124. 17. user_0 should be memberof group_0 on M,H should not on C
  125. 18. memberof fixup task should be successful
  126. 19. user_0 should be memberof group_0 on M,H,C
  127. """
  128. M1 = topo.ms["master1"]
  129. H1 = topo.hs["hub1"]
  130. C1 = topo.cs["consumer1"]
  131. # Step 1 & 2
  132. M1.config.enable_log('audit')
  133. config_memberof(M1)
  134. M1.restart()
  135. H1.config.enable_log('audit')
  136. config_memberof(H1)
  137. H1.restart()
  138. C1.config.enable_log('audit')
  139. config_memberof(C1)
  140. C1.restart()
  141. #Declare lists of users and groups
  142. test_users = []
  143. test_groups = []
  144. # Step 3
  145. #In for loop create users and add them in the user list
  146. #it creates user_0 to user_9 (range is fun)
  147. for i in range(10):
  148. CN = '%s%d' % (USER_CN, i)
  149. users = UserAccounts(M1, SUFFIX)
  150. user_props = TEST_USER_PROPERTIES.copy()
  151. user_props.update({'uid': CN, 'cn': CN, 'sn': '_%s' % CN})
  152. testuser = users.create(properties=user_props)
  153. time.sleep(2)
  154. test_users.append(testuser)
  155. #In for loop create groups and add them to the group list
  156. #it creates group_0 to group_2 (range is fun)
  157. for i in range(3):
  158. CN = '%s%d' % (GROUP_CN, i)
  159. groups = Groups(M1, SUFFIX)
  160. testgroup = groups.create(properties={'cn' : CN})
  161. time.sleep(2)
  162. test_groups.append(testgroup)
  163. # Step 4
  164. #Now start testing by adding differnt user to differn group
  165. if not ds_is_older('1.3.7'):
  166. test_groups[0].remove('objectClass', 'nsMemberOf')
  167. member_dn = test_users[0].dn
  168. grp0_dn = test_groups[0].dn
  169. grp1_dn = test_groups[1].dn
  170. test_groups[0].add_member(member_dn)
  171. time.sleep(5)
  172. # Step 5
  173. for i in [M1, H1, C1]:
  174. _find_memberof(i, member_dn, grp0_dn)
  175. # Step 6
  176. test_groups[1].add_member(test_groups[0].dn)
  177. time.sleep(5)
  178. # Step 7
  179. for i in [grp0_dn, grp1_dn]:
  180. for inst in [M1, H1, C1]:
  181. _find_memberof(inst, member_dn, i)
  182. # Step 8
  183. for i in [M1, H1, C1]:
  184. _find_memberof(i, grp0_dn, grp1_dn)
  185. # Step 9
  186. test_groups[1].remove_member(test_groups[0].dn)
  187. time.sleep(5)
  188. # Step 10
  189. # For negative testcase, we are using assertionerror
  190. for inst in [M1, H1, C1]:
  191. for i in [grp0_dn, member_dn]:
  192. with pytest.raises(AssertionError):
  193. _find_memberof(inst, i, grp1_dn)
  194. # Step 11
  195. test_groups[0].remove_member(member_dn)
  196. time.sleep(5)
  197. # Step 12
  198. for inst in [M1, H1, C1]:
  199. for grp in [grp0_dn, grp1_dn]:
  200. with pytest.raises(AssertionError):
  201. _find_memberof(inst, member_dn, grp)
  202. # Step 13
  203. C1.plugins.disable(name=PLUGIN_MEMBER_OF)
  204. C1.restart()
  205. # Step 14
  206. test_groups[0].add_member(member_dn)
  207. time.sleep(5)
  208. # Step 15
  209. for i in [M1, H1]:
  210. _find_memberof(i, member_dn, grp0_dn)
  211. with pytest.raises(AssertionError):
  212. _find_memberof(C1, member_dn, grp0_dn)
  213. # Step 16
  214. memberof = MemberOfPlugin(C1)
  215. memberof.enable()
  216. C1.restart()
  217. # Step 17
  218. for i in [M1, H1]:
  219. _find_memberof(i, member_dn, grp0_dn)
  220. with pytest.raises(AssertionError):
  221. _find_memberof(C1, member_dn, grp0_dn)
  222. # Step 18
  223. memberof.fixup(SUFFIX)
  224. time.sleep(5)
  225. # Step 19
  226. for i in [M1, H1, C1]:
  227. _find_memberof(i, member_dn, grp0_dn)
  228. @pytest.mark.skipif(ds_is_older('1.4.0'), reason="Not implemented")
  229. def test_scheme_violation_errors_logged(topo):
  230. """Check that ERR messages are verbose enough, if a member entry
  231. doesn't have the appropriate objectclass to support 'memberof' attribute
  232. :id: e2af0aaa-447e-4e85-a5ce-57ae66260d0b
  233. :setup: Standalone instance
  234. :steps:
  235. 1. Enable memberofPlugin and set autoaddoc to nsMemberOf
  236. 2. Restart the instance
  237. 3. Add a user without nsMemberOf attribute
  238. 4. Create a group and add the user to the group
  239. 5. Check that user has memberOf attribute
  240. 6. Check the error log for ".*oc_check_allowed_sv.*USER_DN.*memberOf.*not allowed.*"
  241. and ".*schema violation caught - repair operation.*" patterns
  242. :expectedresults:
  243. 1. Should be successful
  244. 2. Should be successful
  245. 3. Should be successful
  246. 4. Should be successful
  247. 5. User should have the attribute
  248. 6. Errors should be logged
  249. """
  250. inst = topo.ms["master1"]
  251. memberof = MemberOfPlugin(inst)
  252. memberof.enable()
  253. memberof.set_autoaddoc('nsMemberOf')
  254. inst.restart()
  255. users = UserAccounts(inst, SUFFIX)
  256. user_props = TEST_USER_PROPERTIES.copy()
  257. user_props.update({'uid': USER_CN, 'cn': USER_CN, 'sn': USER_CN})
  258. testuser = users.create(properties=user_props)
  259. testuser.remove('objectclass', 'nsMemberOf')
  260. groups = Groups(inst, SUFFIX)
  261. testgroup = groups.create(properties={'cn': GROUP_CN})
  262. testgroup.add('member', testuser.dn)
  263. user_memberof_attr = testuser.get_attr_val_utf8('memberof')
  264. assert user_memberof_attr
  265. log.info('memberOf attr value - '.format(user_memberof_attr))
  266. pattern = ".*oc_check_allowed_sv.*{}.*memberOf.*not allowed.*".format(testuser.dn)
  267. log.info("pattern = %s" % pattern)
  268. assert inst.ds_error_log.match(pattern)
  269. pattern = ".*schema violation caught - repair operation.*"
  270. assert inst.ds_error_log.match(pattern)
  271. @pytest.mark.bz1192099
  272. def test_memberof_with_changelog_reset(topo_m2):
  273. """Test that replication does not break, after DS stop-start, due to changelog reset
  274. :id: 60c11636-55a1-4704-9e09-2c6bcc828de4
  275. :setup: 2 Masters
  276. :steps:
  277. 1. On M1 and M2, Enable memberof
  278. 2. On M1, add 999 entries allowing memberof
  279. 3. On M1, add a group with these 999 entries as members
  280. 4. Stop M1 in between,
  281. when add the group memerof is called and before it is finished the
  282. add, so step 4 should be executed after memberof has started and
  283. before the add has finished
  284. 5. Check that replication is working fine
  285. :expectedresults:
  286. 1. memberof should be enabled
  287. 2. Entries should be added
  288. 3. Add operation should start
  289. 4. M1 should be stopped
  290. 5. Replication should be working fine
  291. """
  292. m1 = topo_m2.ms["master1"]
  293. m2 = topo_m2.ms["master2"]
  294. log.info("Configure memberof on M1 and M2")
  295. memberof = MemberOfPlugin(m1)
  296. memberof.enable()
  297. memberof.set_autoaddoc('nsMemberOf')
  298. m1.restart()
  299. memberof = MemberOfPlugin(m2)
  300. memberof.enable()
  301. memberof.set_autoaddoc('nsMemberOf')
  302. m2.restart()
  303. log.info("On M1, add 999 test entries allowing memberof")
  304. users_list = add_users(topo_m2, 999, DEFAULT_SUFFIX)
  305. log.info("On M1, add a group with these 999 entries as members")
  306. dic_of_attributes = {'cn': ensure_bytes('testgroup'),
  307. 'objectclass': ensure_list_bytes(['top', 'groupOfNames'])}
  308. for user in users_list:
  309. dic_of_attributes.setdefault('member',[])
  310. dic_of_attributes['member'].append(user.dn)
  311. log.info('Adding the test group using async function')
  312. groupdn = 'cn=testgroup,%s' % DEFAULT_SUFFIX
  313. m1.add(Entry((groupdn, dic_of_attributes)))
  314. #shutdown the server in-between adding the group
  315. m1.stop()
  316. #start the server
  317. m1.start()
  318. log.info("Check the log messages for error")
  319. error_msg = "ERR - NSMMReplicationPlugin - ruv_compare_ruv"
  320. assert not m1.ds_error_log.match(error_msg)
  321. log.info("Check that the replication is working fine both ways, M1 <-> M2")
  322. replicas_m1 = Replicas(m1)
  323. replicas_m2 = Replicas(m2)
  324. replicas_m1.test(DEFAULT_SUFFIX, m2)
  325. replicas_m2.test(DEFAULT_SUFFIX, m1)
  326. if __name__ == '__main__':
  327. # Run isolated
  328. # -s for DEBUG mode
  329. CURRENT_FILE = os.path.realpath(__file__)
  330. pytest.main("-s %s" % CURRENT_FILE)