ticket47462_test.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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 logging
  10. import time
  11. import ldap
  12. import pytest
  13. from lib389 import Entry
  14. from lib389._constants import *
  15. from lib389.properties import *
  16. from lib389.topologies import topology_m2
  17. logging.getLogger(__name__).setLevel(logging.DEBUG)
  18. log = logging.getLogger(__name__)
  19. DES_PLUGIN = 'cn=DES,cn=Password Storage Schemes,cn=plugins,cn=config'
  20. AES_PLUGIN = 'cn=AES,cn=Password Storage Schemes,cn=plugins,cn=config'
  21. MMR_PLUGIN = 'cn=Multimaster Replication Plugin,cn=plugins,cn=config'
  22. AGMT_DN = ''
  23. USER_DN = 'cn=test_user,' + DEFAULT_SUFFIX
  24. USER1_DN = 'cn=test_user1,' + DEFAULT_SUFFIX
  25. TEST_REPL_DN = 'cn=test repl,' + DEFAULT_SUFFIX
  26. DES2AES_TASK_DN = 'cn=convert,cn=des2aes,cn=tasks,cn=config'
  27. def test_ticket47462(topology_m2):
  28. """
  29. Test that AES properly replaces DES during an update/restart, and that
  30. replication also works correctly.
  31. """
  32. #
  33. # First set config as if it's an older version. Set DES to use
  34. # libdes-plugin, MMR to depend on DES, delete the existing AES plugin,
  35. # and set a DES password for the replication agreement.
  36. #
  37. # Add an extra attribute to the DES plugin args
  38. #
  39. try:
  40. topology_m2.ms["master1"].modify_s(DES_PLUGIN,
  41. [(ldap.MOD_REPLACE, 'nsslapd-pluginEnabled', 'on')])
  42. except ldap.LDAPError as e:
  43. log.fatal('Failed to enable DES plugin, error: ' +
  44. e.message['desc'])
  45. assert False
  46. try:
  47. topology_m2.ms["master1"].modify_s(DES_PLUGIN,
  48. [(ldap.MOD_ADD, 'nsslapd-pluginarg2', 'description')])
  49. except ldap.LDAPError as e:
  50. log.fatal('Failed to reset DES plugin, error: ' +
  51. e.message['desc'])
  52. assert False
  53. try:
  54. topology_m2.ms["master1"].modify_s(MMR_PLUGIN,
  55. [(ldap.MOD_DELETE,
  56. 'nsslapd-plugin-depends-on-named',
  57. 'AES')])
  58. except ldap.NO_SUCH_ATTRIBUTE:
  59. pass
  60. except ldap.LDAPError as e:
  61. log.fatal('Failed to reset MMR plugin, error: ' +
  62. e.message['desc'])
  63. assert False
  64. #
  65. # Delete the AES plugin
  66. #
  67. try:
  68. topology_m2.ms["master1"].delete_s(AES_PLUGIN)
  69. except ldap.NO_SUCH_OBJECT:
  70. pass
  71. except ldap.LDAPError as e:
  72. log.fatal('Failed to delete AES plugin, error: ' +
  73. e.message['desc'])
  74. assert False
  75. # restart the server so we must use DES plugin
  76. topology_m2.ms["master1"].restart(timeout=10)
  77. #
  78. # Get the agmt dn, and set the password
  79. #
  80. try:
  81. entry = topology_m2.ms["master1"].search_s('cn=config', ldap.SCOPE_SUBTREE,
  82. 'objectclass=nsDS5ReplicationAgreement')
  83. if entry:
  84. agmt_dn = entry[0].dn
  85. log.info('Found agmt dn (%s)' % agmt_dn)
  86. else:
  87. log.fatal('No replication agreements!')
  88. assert False
  89. except ldap.LDAPError as e:
  90. log.fatal('Failed to search for replica credentials: ' +
  91. e.message['desc'])
  92. assert False
  93. try:
  94. properties = {RA_BINDPW: "password"}
  95. topology_m2.ms["master1"].agreement.setProperties(None, agmt_dn, None,
  96. properties)
  97. log.info('Successfully modified replication agreement')
  98. except ValueError:
  99. log.error('Failed to update replica agreement: ' + AGMT_DN)
  100. assert False
  101. #
  102. # Check replication works with the new DES password
  103. #
  104. try:
  105. topology_m2.ms["master1"].add_s(Entry((USER1_DN,
  106. {'objectclass': "top person".split(),
  107. 'sn': 'sn',
  108. 'description': 'DES value to convert',
  109. 'cn': 'test_user'})))
  110. loop = 0
  111. ent = None
  112. while loop <= 10:
  113. try:
  114. ent = topology_m2.ms["master2"].getEntry(USER1_DN, ldap.SCOPE_BASE,
  115. "(objectclass=*)")
  116. break
  117. except ldap.NO_SUCH_OBJECT:
  118. time.sleep(1)
  119. loop += 1
  120. if not ent:
  121. log.fatal('Replication test failed fo user1!')
  122. assert False
  123. else:
  124. log.info('Replication test passed')
  125. except ldap.LDAPError as e:
  126. log.fatal('Failed to add test user: ' + e.message['desc'])
  127. assert False
  128. #
  129. # Add a backend (that has no entries)
  130. #
  131. try:
  132. topology_m2.ms["master1"].backend.create("o=empty", {BACKEND_NAME: "empty"})
  133. except ldap.LDAPError as e:
  134. log.fatal('Failed to create extra/empty backend: ' + e.message['desc'])
  135. assert False
  136. #
  137. # Run the upgrade...
  138. #
  139. topology_m2.ms["master1"].upgrade('online')
  140. topology_m2.ms["master1"].restart()
  141. topology_m2.ms["master2"].restart()
  142. #
  143. # Check that the restart converted existing DES credentials
  144. #
  145. try:
  146. entry = topology_m2.ms["master1"].search_s('cn=config', ldap.SCOPE_SUBTREE,
  147. 'nsDS5ReplicaCredentials=*')
  148. if entry:
  149. val = entry[0].getValue('nsDS5ReplicaCredentials')
  150. if val.startswith('{AES-'):
  151. log.info('The DES credentials have been converted to AES')
  152. else:
  153. log.fatal('Failed to convert credentials from DES to AES!')
  154. assert False
  155. else:
  156. log.fatal('Failed to find entries with nsDS5ReplicaCredentials')
  157. assert False
  158. except ldap.LDAPError as e:
  159. log.fatal('Failed to search for replica credentials: ' +
  160. e.message['desc'])
  161. assert False
  162. #
  163. # Check that the AES plugin exists, and has all the attributes listed in
  164. # DES plugin. The attributes might not be in the expected order so check
  165. # all the attributes.
  166. #
  167. try:
  168. entry = topology_m2.ms["master1"].search_s(AES_PLUGIN, ldap.SCOPE_BASE,
  169. 'objectclass=*')
  170. if not entry[0].hasValue('nsslapd-pluginarg0', 'description') and \
  171. not entry[0].hasValue('nsslapd-pluginarg1', 'description') and \
  172. not entry[0].hasValue('nsslapd-pluginarg2', 'description'):
  173. log.fatal('The AES plugin did not have the DES attribute copied ' +
  174. 'over correctly')
  175. assert False
  176. else:
  177. log.info('The AES plugin was correctly setup')
  178. except ldap.LDAPError as e:
  179. log.fatal('Failed to find AES plugin: ' + e.message['desc'])
  180. assert False
  181. #
  182. # Check that the MMR plugin was updated
  183. #
  184. try:
  185. entry = topology_m2.ms["master1"].search_s(MMR_PLUGIN, ldap.SCOPE_BASE,
  186. 'objectclass=*')
  187. if not entry[0].hasValue('nsslapd-plugin-depends-on-named', 'AES'):
  188. log.fatal('The MMR Plugin was not correctly updated')
  189. assert False
  190. else:
  191. log.info('The MMR plugin was correctly updated')
  192. except ldap.LDAPError as e:
  193. log.fatal('Failed to find AES plugin: ' + e.message['desc'])
  194. assert False
  195. #
  196. # Check that the DES plugin was correctly updated
  197. #
  198. try:
  199. entry = topology_m2.ms["master1"].search_s(DES_PLUGIN, ldap.SCOPE_BASE,
  200. 'objectclass=*')
  201. if not entry[0].hasValue('nsslapd-pluginPath', 'libpbe-plugin'):
  202. log.fatal('The DES Plugin was not correctly updated')
  203. assert False
  204. else:
  205. log.info('The DES plugin was correctly updated')
  206. except ldap.LDAPError as e:
  207. log.fatal('Failed to find AES plugin: ' + e.message['desc'])
  208. assert False
  209. #
  210. # Check replication one last time
  211. #
  212. try:
  213. topology_m2.ms["master1"].add_s(Entry((USER_DN,
  214. {'objectclass': "top person".split(),
  215. 'sn': 'sn',
  216. 'cn': 'test_user'})))
  217. loop = 0
  218. ent = None
  219. while loop <= 10:
  220. try:
  221. ent = topology_m2.ms["master2"].getEntry(USER_DN, ldap.SCOPE_BASE,
  222. "(objectclass=*)")
  223. break
  224. except ldap.NO_SUCH_OBJECT:
  225. time.sleep(1)
  226. loop += 1
  227. if not ent:
  228. log.fatal('Replication test failed!')
  229. assert False
  230. else:
  231. log.info('Replication test passed')
  232. except ldap.LDAPError as e:
  233. log.fatal('Failed to add test user: ' + e.message['desc'])
  234. assert False
  235. # Check the entry
  236. log.info('Entry before running task...')
  237. try:
  238. entry = topology_m2.ms["master1"].search_s(USER1_DN,
  239. ldap.SCOPE_BASE,
  240. 'objectclass=*')
  241. if entry:
  242. print(str(entry))
  243. else:
  244. log.fatal('Failed to find entries')
  245. assert False
  246. except ldap.LDAPError as e:
  247. log.fatal('Failed to search for entries: ' +
  248. e.message['desc'])
  249. assert False
  250. #
  251. # Test the DES2AES Task on USER1_DN
  252. #
  253. try:
  254. topology_m2.ms["master1"].add_s(Entry((DES2AES_TASK_DN,
  255. {'objectclass': ['top',
  256. 'extensibleObject'],
  257. 'suffix': DEFAULT_SUFFIX,
  258. 'cn': 'convert'})))
  259. except ldap.LDAPError as e:
  260. log.fatal('Failed to add task entry: ' + e.message['desc'])
  261. assert False
  262. # Wait for task
  263. task_entry = Entry(DES2AES_TASK_DN)
  264. (done, exitCode) = topology_m2.ms["master1"].tasks.checkTask(task_entry, True)
  265. if exitCode:
  266. log.fatal("Error: des2aes task exited with %d" % (exitCode))
  267. assert False
  268. # Check the entry
  269. try:
  270. entry = topology_m2.ms["master1"].search_s(USER1_DN,
  271. ldap.SCOPE_BASE,
  272. 'objectclass=*')
  273. if entry:
  274. val = entry[0].getValue('description')
  275. print(str(entry[0]))
  276. if val.startswith('{AES-'):
  277. log.info('Task: DES credentials have been converted to AES')
  278. else:
  279. log.fatal('Task: Failed to convert credentials from DES to ' +
  280. 'AES! (%s)' % (val))
  281. assert False
  282. else:
  283. log.fatal('Failed to find entries')
  284. assert False
  285. except ldap.LDAPError as e:
  286. log.fatal('Failed to search for entries: ' +
  287. e.message['desc'])
  288. assert False
  289. if __name__ == '__main__':
  290. # Run isolated
  291. # -s for DEBUG mode
  292. CURRENT_FILE = os.path.realpath(__file__)
  293. pytest.main("-s %s" % CURRENT_FILE)