ticket47714_test.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. import os
  2. import sys
  3. import time
  4. import ldap
  5. import logging
  6. import socket
  7. import pytest
  8. import shutil
  9. from lib389 import DirSrv, Entry, tools
  10. from lib389.tools import DirSrvTools
  11. from lib389._constants import *
  12. from lib389.properties import *
  13. from constants import *
  14. log = logging.getLogger(__name__)
  15. installation_prefix = None
  16. ACCT_POLICY_CONFIG_DN = 'cn=config,cn=%s,cn=plugins,cn=config' % PLUGIN_ACCT_POLICY
  17. ACCT_POLICY_DN = 'cn=Account Inactivation Pplicy,%s' % SUFFIX
  18. INACTIVITY_LIMIT = '9'
  19. SEARCHFILTER = '(objectclass=*)'
  20. TEST_USER = 'ticket47714user'
  21. TEST_USER_DN = 'uid=%s,%s' % (TEST_USER, SUFFIX)
  22. TEST_USER_PW = '%s' % TEST_USER
  23. class TopologyStandalone(object):
  24. def __init__(self, standalone):
  25. standalone.open()
  26. self.standalone = standalone
  27. @pytest.fixture(scope="module")
  28. def topology(request):
  29. '''
  30. This fixture is used to standalone topology for the 'module'.
  31. At the beginning, It may exists a standalone instance.
  32. It may also exists a backup for the standalone instance.
  33. Principle:
  34. If standalone instance exists:
  35. restart it
  36. If backup of standalone exists:
  37. create/rebind to standalone
  38. restore standalone instance from backup
  39. else:
  40. Cleanup everything
  41. remove instance
  42. remove backup
  43. Create instance
  44. Create backup
  45. '''
  46. global installation_prefix
  47. if installation_prefix:
  48. args_instance[SER_DEPLOYED_DIR] = installation_prefix
  49. standalone = DirSrv(verbose=False)
  50. # Args for the standalone instance
  51. args_instance[SER_HOST] = HOST_STANDALONE
  52. args_instance[SER_PORT] = PORT_STANDALONE
  53. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  54. args_standalone = args_instance.copy()
  55. standalone.allocate(args_standalone)
  56. # Get the status of the backups
  57. backup_standalone = standalone.checkBackupFS()
  58. # Get the status of the instance and restart it if it exists
  59. instance_standalone = standalone.exists()
  60. if instance_standalone:
  61. # assuming the instance is already stopped, just wait 5 sec max
  62. standalone.stop(timeout=5)
  63. try:
  64. standalone.start(timeout=10)
  65. except ldap.SERVER_DOWN:
  66. pass
  67. if backup_standalone:
  68. # The backup exist, assuming it is correct
  69. # we just re-init the instance with it
  70. if not instance_standalone:
  71. standalone.create()
  72. # Used to retrieve configuration information (dbdir, confdir...)
  73. standalone.open()
  74. # restore standalone instance from backup
  75. standalone.stop(timeout=10)
  76. standalone.restoreFS(backup_standalone)
  77. standalone.start(timeout=10)
  78. else:
  79. # We should be here only in two conditions
  80. # - This is the first time a test involve standalone instance
  81. # - Something weird happened (instance/backup destroyed)
  82. # so we discard everything and recreate all
  83. # Remove the backup. So even if we have a specific backup file
  84. # (e.g backup_standalone) we clear backup that an instance may have created
  85. if backup_standalone:
  86. standalone.clearBackupFS()
  87. # Remove the instance
  88. if instance_standalone:
  89. standalone.delete()
  90. # Create the instance
  91. standalone.create()
  92. # Used to retrieve configuration information (dbdir, confdir...)
  93. standalone.open()
  94. # Time to create the backups
  95. standalone.stop(timeout=10)
  96. standalone.backupfile = standalone.backupFS()
  97. standalone.start(timeout=10)
  98. # clear the tmp directory
  99. standalone.clearTmpDir(__file__)
  100. #
  101. # Here we have standalone instance up and running
  102. # Either coming from a backup recovery
  103. # or from a fresh (re)init
  104. # Time to return the topology
  105. return TopologyStandalone(standalone)
  106. def _header(topology, label):
  107. topology.standalone.log.info("\n\n###############################################")
  108. topology.standalone.log.info("#######")
  109. topology.standalone.log.info("####### %s" % label)
  110. topology.standalone.log.info("#######")
  111. topology.standalone.log.info("###############################################")
  112. def _uniqueness_config_entry(topology, name=None):
  113. if not name:
  114. return None
  115. ent = topology.standalone.getEntry("cn=%s,%s" % (PLUGIN_ATTR_UNIQUENESS, DN_PLUGIN), ldap.SCOPE_BASE,
  116. "(objectclass=nsSlapdPlugin)",
  117. ['objectClass', 'cn', 'nsslapd-pluginPath', 'nsslapd-pluginInitfunc',
  118. 'nsslapd-pluginType', 'nsslapd-pluginEnabled', 'nsslapd-plugin-depends-on-type',
  119. 'nsslapd-pluginId', 'nsslapd-pluginVersion', 'nsslapd-pluginVendor',
  120. 'nsslapd-pluginDescription'])
  121. ent.dn = "cn=%s uniqueness,%s" % (name, DN_PLUGIN)
  122. return ent
  123. def test_ticket47714_init(topology):
  124. """
  125. 1. Add account policy entry to the DB
  126. 2. Add a test user to the DB
  127. """
  128. _header(topology, 'Testing Ticket 47714 - [RFE] Update lastLoginTime also in Account Policy plugin if account lockout is based on passwordExpirationTime.')
  129. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  130. log.info("\n######################### Adding Account Policy entry: %s ######################\n" % ACCT_POLICY_DN)
  131. topology.standalone.add_s(Entry((ACCT_POLICY_DN, {'objectclass': "top ldapsubentry extensibleObject accountpolicy".split(),
  132. 'accountInactivityLimit': INACTIVITY_LIMIT})))
  133. log.info("\n######################### Adding Test User entry: %s ######################\n" % TEST_USER_DN)
  134. topology.standalone.add_s(Entry((TEST_USER_DN, {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
  135. 'cn': TEST_USER,
  136. 'sn': TEST_USER,
  137. 'givenname': TEST_USER,
  138. 'userPassword': TEST_USER_PW,
  139. 'acctPolicySubentry': ACCT_POLICY_DN})))
  140. log.info("\n######################### Adding cos entry ######################\n")
  141. def test_ticket47714_run_0(topology):
  142. """
  143. Check this change has no inpact to the existing functionality.
  144. 1. Set account policy config without the new attr alwaysRecordLoginAttr
  145. 2. Bind as a test user
  146. 3. Bind as the test user again and check the lastLoginTime is updated
  147. 4. Waint longer than the accountInactivityLimit time and bind as the test user,
  148. which should fail with CONSTANT_VIOLATION.
  149. """
  150. _header(topology, 'Account Policy - No new attr alwaysRecordLoginAttr in config')
  151. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  152. # Modify Account Policy config entry
  153. topology.standalone.modify_s(ACCT_POLICY_CONFIG_DN, [(ldap.MOD_REPLACE, 'alwaysrecordlogin', 'yes'),
  154. (ldap.MOD_REPLACE, 'stateattrname', 'lastLoginTime'),
  155. (ldap.MOD_REPLACE, 'altstateattrname', 'createTimestamp'),
  156. (ldap.MOD_REPLACE, 'specattrname', 'acctPolicySubentry'),
  157. (ldap.MOD_REPLACE, 'limitattrname', 'accountInactivityLimit')])
  158. # Enable the plugins
  159. topology.standalone.plugins.enable(name=PLUGIN_ACCT_POLICY)
  160. topology.standalone.restart(timeout=120)
  161. log.info("\n######################### Bind as %s ######################\n" % TEST_USER_DN)
  162. try:
  163. topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PW)
  164. except ldap.CONSTRAINT_VIOLATION, e:
  165. log.error('CONSTRAINT VIOLATION ' + e.message['desc'])
  166. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  167. entry = topology.standalone.search_s(TEST_USER_DN, ldap.SCOPE_BASE, SEARCHFILTER, ['lastLoginTime'])
  168. lastLoginTime0 = entry[0].lastLoginTime
  169. time.sleep(2)
  170. log.info("\n######################### Bind as %s again ######################\n" % TEST_USER_DN)
  171. try:
  172. topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PW)
  173. except ldap.CONSTRAINT_VIOLATION, e:
  174. log.error('CONSTRAINT VIOLATION ' + e.message['desc'])
  175. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  176. entry = topology.standalone.search_s(TEST_USER_DN, ldap.SCOPE_BASE, SEARCHFILTER, ['lastLoginTime'])
  177. lastLoginTime1 = entry[0].lastLoginTime
  178. log.info("First lastLoginTime: %s, Second lastLoginTime: %s" % (lastLoginTime0, lastLoginTime1))
  179. assert lastLoginTime0 < lastLoginTime1
  180. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  181. entry = topology.standalone.search_s(ACCT_POLICY_DN, ldap.SCOPE_BASE, SEARCHFILTER)
  182. log.info("\n######################### %s ######################\n" % ACCT_POLICY_CONFIG_DN)
  183. log.info("accountInactivityLimit: %s" % entry[0].accountInactivityLimit)
  184. log.info("\n######################### %s DONE ######################\n" % ACCT_POLICY_CONFIG_DN)
  185. time.sleep(10)
  186. log.info("\n######################### Bind as %s again to fail ######################\n" % TEST_USER_DN)
  187. try:
  188. topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PW)
  189. except ldap.CONSTRAINT_VIOLATION, e:
  190. log.info('CONSTRAINT VIOLATION ' + e.message['desc'])
  191. log.info("%s was successfully inactivated." % TEST_USER_DN)
  192. pass
  193. def test_ticket47714_run_1(topology):
  194. """
  195. Verify a new config attr alwaysRecordLoginAttr
  196. 1. Set account policy config with the new attr alwaysRecordLoginAttr: lastLoginTime
  197. Note: bogus attr is set to stateattrname.
  198. altstateattrname type value is used for checking whether the account is idle or not.
  199. 2. Bind as a test user
  200. 3. Bind as the test user again and check the alwaysRecordLoginAttr: lastLoginTime is updated
  201. """
  202. _header(topology, 'Account Policy - With new attr alwaysRecordLoginAttr in config')
  203. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  204. topology.standalone.modify_s(TEST_USER_DN, [(ldap.MOD_DELETE, 'lastLoginTime', None)])
  205. # Modify Account Policy config entry
  206. topology.standalone.modify_s(ACCT_POLICY_CONFIG_DN, [(ldap.MOD_REPLACE, 'alwaysrecordlogin', 'yes'),
  207. (ldap.MOD_REPLACE, 'stateattrname', 'bogus'),
  208. (ldap.MOD_REPLACE, 'altstateattrname', 'modifyTimestamp'),
  209. (ldap.MOD_REPLACE, 'alwaysRecordLoginAttr', 'lastLoginTime'),
  210. (ldap.MOD_REPLACE, 'specattrname', 'acctPolicySubentry'),
  211. (ldap.MOD_REPLACE, 'limitattrname', 'accountInactivityLimit')])
  212. # Enable the plugins
  213. topology.standalone.plugins.enable(name=PLUGIN_ACCT_POLICY)
  214. topology.standalone.restart(timeout=120)
  215. log.info("\n######################### Bind as %s ######################\n" % TEST_USER_DN)
  216. try:
  217. topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PW)
  218. except ldap.CONSTRAINT_VIOLATION, e:
  219. log.error('CONSTRAINT VIOLATION ' + e.message['desc'])
  220. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  221. entry = topology.standalone.search_s(TEST_USER_DN, ldap.SCOPE_BASE, SEARCHFILTER, ['lastLoginTime'])
  222. lastLoginTime0 = entry[0].lastLoginTime
  223. time.sleep(2)
  224. log.info("\n######################### Bind as %s again ######################\n" % TEST_USER_DN)
  225. try:
  226. topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PW)
  227. except ldap.CONSTRAINT_VIOLATION, e:
  228. log.error('CONSTRAINT VIOLATION ' + e.message['desc'])
  229. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  230. entry = topology.standalone.search_s(TEST_USER_DN, ldap.SCOPE_BASE, SEARCHFILTER, ['lastLoginTime'])
  231. lastLoginTime1 = entry[0].lastLoginTime
  232. log.info("First lastLoginTime: %s, Second lastLoginTime: %s" % (lastLoginTime0, lastLoginTime1))
  233. assert lastLoginTime0 < lastLoginTime1
  234. topology.standalone.log.info("ticket47714 was successfully verified.");
  235. def test_ticket47714_final(topology):
  236. log.info("\n######################### Adding Account Policy entry: %s ######################\n" % ACCT_POLICY_DN)
  237. # Enabled the plugins
  238. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  239. topology.standalone.plugins.disable(name=PLUGIN_ACCT_POLICY)
  240. topology.standalone.stop(timeout=10)
  241. def run_isolated():
  242. '''
  243. run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
  244. To run isolated without py.test, you need to
  245. - edit this file and comment '@pytest.fixture' line before 'topology' function.
  246. - set the installation prefix
  247. - run this program
  248. '''
  249. global installation_prefix
  250. installation_prefix = None
  251. topo = topology(True)
  252. test_ticket47714_init(topo)
  253. test_ticket47714_run_0(topo)
  254. test_ticket47714_run_1(topo)
  255. test_ticket47714_final(topo)
  256. if __name__ == '__main__':
  257. run_isolated()