ticket48228_test.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. # --- BEGIN COPYRIGHT BLOCK ---
  2. # Copyright (C) 2015 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 os
  10. import sys
  11. import time
  12. import ldap
  13. import logging
  14. import pytest
  15. from lib389 import DirSrv, Entry, tools, tasks
  16. from lib389.tools import DirSrvTools
  17. from lib389._constants import *
  18. from lib389.properties import *
  19. from lib389.tasks import *
  20. log = logging.getLogger(__name__)
  21. installation_prefix = None
  22. # Assuming DEFAULT_SUFFIX is "dc=example,dc=com", otherwise it does not work... :(
  23. SUBTREE_CONTAINER = 'cn=nsPwPolicyContainer,' + DEFAULT_SUFFIX
  24. SUBTREE_PWPDN = 'cn=nsPwPolicyEntry,' + DEFAULT_SUFFIX
  25. SUBTREE_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cdc\3Dexample\2Cdc\3Dcom,' + SUBTREE_CONTAINER
  26. SUBTREE_COS_TMPLDN = 'cn=nsPwTemplateEntry,' + DEFAULT_SUFFIX
  27. SUBTREE_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cdc\3Dexample\2Cdc\3Dcom,' + SUBTREE_CONTAINER
  28. SUBTREE_COS_DEF = 'cn=nsPwPolicy_CoS,' + DEFAULT_SUFFIX
  29. USER1_DN = 'uid=user1,' + DEFAULT_SUFFIX
  30. USER2_DN = 'uid=user2,' + DEFAULT_SUFFIX
  31. class TopologyStandalone(object):
  32. def __init__(self, standalone):
  33. standalone.open()
  34. self.standalone = standalone
  35. @pytest.fixture(scope="module")
  36. def topology(request):
  37. '''
  38. This fixture is used to standalone topology for the 'module'.
  39. '''
  40. global installation_prefix
  41. if installation_prefix:
  42. args_instance[SER_DEPLOYED_DIR] = installation_prefix
  43. standalone = DirSrv(verbose=False)
  44. # Args for the standalone instance
  45. args_instance[SER_HOST] = HOST_STANDALONE
  46. args_instance[SER_PORT] = PORT_STANDALONE
  47. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  48. args_standalone = args_instance.copy()
  49. standalone.allocate(args_standalone)
  50. # Get the status of the instance and restart it if it exists
  51. instance_standalone = standalone.exists()
  52. # Remove the instance
  53. if instance_standalone:
  54. standalone.delete()
  55. # Create the instance
  56. standalone.create()
  57. # Used to retrieve configuration information (dbdir, confdir...)
  58. standalone.open()
  59. def fin():
  60. standalone.delete()
  61. request.addfinalizer(fin)
  62. # Here we have standalone instance up and running
  63. return TopologyStandalone(standalone)
  64. def set_global_pwpolicy(topology, inhistory):
  65. log.info(" +++++ Enable global password policy +++++\n")
  66. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  67. # Enable password policy
  68. try:
  69. topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
  70. except ldap.LDAPError as e:
  71. log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
  72. assert False
  73. log.info(" Set global password history on\n")
  74. try:
  75. topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordHistory', 'on')])
  76. except ldap.LDAPError as e:
  77. log.error('Failed to set passwordHistory: error ' + e.message['desc'])
  78. assert False
  79. log.info(" Set global passwords in history\n")
  80. try:
  81. count = "%d" % inhistory
  82. topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordInHistory', count)])
  83. except ldap.LDAPError as e:
  84. log.error('Failed to set passwordInHistory: error ' + e.message['desc'])
  85. assert False
  86. def set_subtree_pwpolicy(topology):
  87. log.info(" +++++ Enable subtree level password policy +++++\n")
  88. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  89. log.info(" Add the container")
  90. try:
  91. topology.standalone.add_s(Entry((SUBTREE_CONTAINER, {'objectclass': 'top nsContainer'.split(),
  92. 'cn': 'nsPwPolicyContainer'})))
  93. except ldap.LDAPError as e:
  94. log.error('Failed to add subtree container: error ' + e.message['desc'])
  95. assert False
  96. log.info(" Add the password policy subentry {passwordHistory: on, passwordInHistory: 6}")
  97. try:
  98. topology.standalone.add_s(Entry((SUBTREE_PWP, {'objectclass': 'top ldapsubentry passwordpolicy'.split(),
  99. 'cn': SUBTREE_PWPDN,
  100. 'passwordMustChange': 'off',
  101. 'passwordExp': 'off',
  102. 'passwordHistory': 'on',
  103. 'passwordInHistory': '6',
  104. 'passwordMinAge': '0',
  105. 'passwordChange': 'on',
  106. 'passwordStorageScheme': 'clear'})))
  107. except ldap.LDAPError as e:
  108. log.error('Failed to add passwordpolicy: error ' + e.message['desc'])
  109. assert False
  110. log.info(" Add the COS template")
  111. try:
  112. topology.standalone.add_s(Entry((SUBTREE_COS_TMPL, {'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
  113. 'cn': SUBTREE_PWPDN,
  114. 'cosPriority': '1',
  115. 'cn': SUBTREE_COS_TMPLDN,
  116. 'pwdpolicysubentry': SUBTREE_PWP})))
  117. except ldap.LDAPError as e:
  118. log.error('Failed to add COS template: error ' + e.message['desc'])
  119. assert False
  120. log.info(" Add the COS definition")
  121. try:
  122. topology.standalone.add_s(Entry((SUBTREE_COS_DEF, {'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
  123. 'cn': SUBTREE_PWPDN,
  124. 'costemplatedn': SUBTREE_COS_TMPL,
  125. 'cosAttribute': 'pwdpolicysubentry default operational-default'})))
  126. except ldap.LDAPError as e:
  127. log.error('Failed to add COS def: error ' + e.message['desc'])
  128. assert False
  129. def check_passwd_inhistory(topology, user, cpw, passwd):
  130. inhistory = 0
  131. log.info(" Bind as {%s,%s}" % (user, cpw))
  132. topology.standalone.simple_bind_s(user, cpw)
  133. try:
  134. topology.standalone.modify_s(user, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
  135. except ldap.LDAPError as e:
  136. log.info(' The password ' + passwd + ' of user' + USER1_DN + ' in history: error ' + e.message['desc'])
  137. inhistory = 1
  138. time.sleep(1)
  139. return inhistory
  140. def update_passwd(topology, user, passwd, times):
  141. cpw = passwd
  142. for i in range(times):
  143. log.info(" Bind as {%s,%s}" % (user, cpw))
  144. topology.standalone.simple_bind_s(user, cpw)
  145. cpw = 'password%d' % i
  146. try:
  147. topology.standalone.modify_s(user, [(ldap.MOD_REPLACE, 'userpassword', cpw)])
  148. except ldap.LDAPError as e:
  149. log.fatal('test_ticket48228: Failed to update the password ' + cpw + ' of user ' + user + ': error ' + e.message['desc'])
  150. assert False
  151. time.sleep(1)
  152. # checking the first password, which is supposed to be in history
  153. inhistory = check_passwd_inhistory(topology, user, cpw, passwd)
  154. assert inhistory == 1
  155. def test_ticket48228_test_global_policy(topology):
  156. """
  157. Check global password policy
  158. """
  159. log.info(' Set inhistory = 6')
  160. set_global_pwpolicy(topology, 6)
  161. log.info(' Bind as directory manager')
  162. log.info("Bind as %s" % DN_DM)
  163. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  164. log.info(' Add an entry' + USER1_DN)
  165. try:
  166. topology.standalone.add_s(Entry((USER1_DN, {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
  167. 'sn': '1',
  168. 'cn': 'user 1',
  169. 'uid': 'user1',
  170. 'givenname': 'user',
  171. 'mail': '[email protected]',
  172. 'userpassword': 'password'})))
  173. except ldap.LDAPError as e:
  174. log.fatal('test_ticket48228: Failed to add user' + USER1_DN + ': error ' + e.message['desc'])
  175. assert False
  176. log.info(' Update the password of ' + USER1_DN + ' 6 times')
  177. update_passwd(topology, USER1_DN, 'password', 6)
  178. log.info(' Set inhistory = 4')
  179. set_global_pwpolicy(topology, 4)
  180. log.info(' checking the first password, which is supposed NOT to be in history any more')
  181. cpw = 'password%d' % 5
  182. tpw = 'password'
  183. inhistory = check_passwd_inhistory(topology, USER1_DN, cpw, tpw)
  184. assert inhistory == 0
  185. log.info(' checking the second password, which is supposed NOT to be in history any more')
  186. cpw = tpw
  187. tpw = 'password%d' % 0
  188. inhistory = check_passwd_inhistory(topology, USER1_DN, cpw, tpw)
  189. assert inhistory == 0
  190. log.info(' checking the third password, which is supposed NOT to be in history any more')
  191. cpw = tpw
  192. tpw = 'password%d' % 1
  193. inhistory = check_passwd_inhistory(topology, USER1_DN, cpw, tpw)
  194. assert inhistory == 0
  195. log.info(' checking the sixth password, which is supposed to be in history')
  196. cpw = tpw
  197. tpw = 'password%d' % 5
  198. inhistory = check_passwd_inhistory(topology, USER1_DN, cpw, tpw)
  199. assert inhistory == 1
  200. log.info("Global policy was successfully verified.")
  201. def test_ticket48228_test_subtree_policy(topology):
  202. """
  203. Check subtree level password policy
  204. """
  205. log.info(' Set inhistory = 6')
  206. set_subtree_pwpolicy(topology)
  207. log.info(' Bind as directory manager')
  208. log.info("Bind as %s" % DN_DM)
  209. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  210. log.info(' Add an entry' + USER2_DN)
  211. try:
  212. topology.standalone.add_s(Entry((USER2_DN, {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
  213. 'sn': '2',
  214. 'cn': 'user 2',
  215. 'uid': 'user2',
  216. 'givenname': 'user',
  217. 'mail': '[email protected]',
  218. 'userpassword': 'password'})))
  219. except ldap.LDAPError as e:
  220. log.fatal('test_ticket48228: Failed to add user' + USER2_DN + ': error ' + e.message['desc'])
  221. assert False
  222. log.info(' Update the password of ' + USER2_DN + ' 6 times')
  223. update_passwd(topology, USER2_DN, 'password', 6)
  224. log.info(' Set inhistory = 4')
  225. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  226. try:
  227. topology.standalone.modify_s(SUBTREE_PWP, [(ldap.MOD_REPLACE, 'passwordInHistory', '4')])
  228. except ldap.LDAPError as e:
  229. log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
  230. assert False
  231. log.info(' checking the first password, which is supposed NOT to be in history any more')
  232. cpw = 'password%d' % 5
  233. tpw = 'password'
  234. inhistory = check_passwd_inhistory(topology, USER2_DN, cpw, tpw)
  235. assert inhistory == 0
  236. log.info(' checking the second password, which is supposed NOT to be in history any more')
  237. cpw = tpw
  238. tpw = 'password%d' % 1
  239. inhistory = check_passwd_inhistory(topology, USER2_DN, cpw, tpw)
  240. assert inhistory == 0
  241. log.info(' checking the third password, which is supposed NOT to be in history any more')
  242. cpw = tpw
  243. tpw = 'password%d' % 2
  244. inhistory = check_passwd_inhistory(topology, USER2_DN, cpw, tpw)
  245. assert inhistory == 0
  246. log.info(' checking the six password, which is supposed to be in history')
  247. cpw = tpw
  248. tpw = 'password%d' % 5
  249. inhistory = check_passwd_inhistory(topology, USER2_DN, cpw, tpw)
  250. assert inhistory == 1
  251. log.info("Subtree level policy was successfully verified.")
  252. if __name__ == '__main__':
  253. # Run isolated
  254. # -s for DEBUG mode
  255. CURRENT_FILE = os.path.realpath(__file__)
  256. pytest.main("-s %s" % CURRENT_FILE)